The React of notes

React development dependencies

  • React: Contains the core code necessary for React
  • React -dom: The core code required for react rendering on different platforms
  • Babel: A tool to convert JSX to React code

Write the React code in the script tag

<script type='text/babel'>
    let message = 'hello world'
    ReactDom.render(<h2>{message}</h2>, document.getElementById('#app'))
</script>
Copy the code

Class encapsulated component

Class App extends React.Component {constructor() {super() this.state = {message: 'hello world', movies: [1, 2, 3]}} to render () {{/ * JSX * /} return (< h2 > {this. State. The message} < / h2 > < ul > {this. State. Movies. The map ((item, index) => { return (<li>{item}</li>) }) } </ul> ) } } ReactDom.render(<App />, document.getElementById('#app'))Copy the code

Know the JSX

  • JSX is a JavaScript syntactic extension, also known in many places as JavaScript XML
  • It describes our UI interface, and JSX is perfectly compatible with JavaScript

JSX writing specification:

  • The top layer of JSX can only have one root element, so we often wrap a div element around it
  • Labels in JSX can be single or double labels, but if they are single, they must end with />

The use of the JSX

  • When the variable is number, string, or array, the content can be displayed directly
  • When a variable is null, undefined, or Boolean, the content is null. You can convert this data to a string if you want to display it on a page
  • JSX can embed JS expressions

JSX binding properties

<h2 title={title}></h2> {/ HtmlFor */} <div className={'box title '+ (active? 'active' : ')} > < / div > {binding style / * * /} < div style = {{color: 'red', fontSize: '50 px'}} > < / div >Copy the code

JSX binding events

React doesn’t help us bind this, so undefined

Constructor () {this.btnclick = this.btnclick.bind (this)} render() {return (<div> {/* 选 一 */} <button OnClick ={this.btnClick}> button 1</button> {/* <button onClick={this.increment}>+1</button> {/* Just pass in an arrow function, */} < buttonclick ={(e) => {this.decrement("why")}}>-1</button> </div>)} btnClick() { console.log(this.state.message); } increment = () => { console.log(this.state.counter); } decrement(name) { console.log(this.state.counter, name); }Copy the code

Conditions apply colours to a drawing

Render () {const {isLogin} = this.state // let welcome = null let btnText = null if (isLogin) {welcome = </h2> btnText = 'exit'} else {welcome = <h2> btnText = 'login'} return (<div> {welcome}) <button>{btnText}</button> {/* 2. */} <button>{isLogin? 'exit' : 'login'} < / button > {/ * 2. The solution 3: logic and && * /} {isLogin && < h2 > hello < / h2 >} < / div >)}Copy the code

The essence of the JSX

JSX just React. CreateElement (Component, props,… The syntactic sugar of the children function

All JSX will eventually be converted to function calls to React. CreateElement

CreateElement takes three arguments:

  • Type: If it is a label element, use the string of the label name directly, if it is a component element, use the component name directly
  • Parameter two config: All properties in JSX are stored in Config as properties and values of objects
  • Three children: Stores the contents of the label as an array of children

React.createElement will eventually create a ReactElement object

  • React uses ReactElement objects to form a JavaScript object tree
  • JavaScript object tree is the Virtual DOM

Why use the virtual DOM instead of directly modifying the real DOM?

  • The original development mode is difficult to track the change of the state, which is not convenient for us to debug the application
  • The performance of manipulating the real DOM is low, the objects created from document.createElement are very complex, and manipulating the DOM causes browser backflow and redrawing.

React scaffolding

  • React Scaffolding itself depends on Node, so install the Node environment, download it from the Node website, and run the node–version command to check the Node version
  • Install yarn using NPM. NPM install yarn -g
  • Install scaffolding, NPM install create-react-app-g

Create the React project

Create-react-app project name (note that the project name cannot contain uppercase letters)

Webpack in scaffolding

If we want to see webPack configuration information

  • Json file: “eject”: “react-scripts eject”
  • Yarn eject is irreversible on the command line

Re-scaffolding the file structure of the project created in scaffolding

// Create an index.js file in SRC. // Create an index.js file in SRC. // Create an index.js file in SRC. Import React from 'React' import ReactDOM from 'react-dom' import App from 'app.js' Reactdom.render (<App />, document.getelementbyid ('root')) // If you don't want to write too much code in reactdom.render, You can extract a separate component app.js // app.js file import React, { Component } from 'react' export default class App extends Component { render() { return <h2>Hello React</h2> } }Copy the code

componentization

Class components

// The component name must begin with a capital letter, // Class components must extend the render function export default class App extends react.ponent {// Class components must implement the render function export default class App extends react.ponent { Constructor () {// Optionally, data is initialized from constructor, Return [<div></div> <div></div> </div> <div></div>]}} // function components // function components have their own characteristics (the following characteristics in the case of no hook) // no life cycle, can be updated and mounted, Export default function App() {return (<div>Hello World</div>)}Copy the code

Basic life cycle functions

  • constructor

    • If there is no initialization state or method binding, there is no need to implement a constructor for the React component
    • Constructor usually does only two things: initialize state and bind an instance of the event (this).
  • ComponentDidMount: Called immediately after the component is mounted (inserted into the DOM count)

    • Dom-dependent operations can be performed here,
    • This is the best place to send a network request (official advice)
    • You can add some subscriptions here
  • ComponentDidUpdate: is called immediately after an update, and does not execute this method for the first rendering

  • ComponentWillUnmount: Called directly before the component is unmounted and destroyed

    • Perform the necessary cleanup operations in this method
  • There are some other life cycle can view the official document: zh-hans.reactjs.org/docs/react-…

Intercomponent communication

// The parent component communicates with the parent component // the parent component passes data to the child component as a property = value // the child component gets data from the parent component using the props parameter from 'prop-types' class App extends React.Component { render() { <h1>hello, {this.props. Name}</h1>}} // Set the props parameter of the App component to app.propTypes = {name: PropTypes. String. IsRequired / / string type, and set up the App is will pass} / / component props parameters. The default value of App defaultProps = {name: // The function component and the class component set the props argument in the same way // the child component passes the message to the parent component // the parent component passes a callback function, Import React, {Component} from 'React '; Class CounterButton extends Component {render() {const {onClick} = this.props; return <button onClick={onClick}>+1</button> } } export default class App extends Component { constructor(props) { super(props); This. State = {counter: 0}} render() {return (<div> <h2> {this.state.counter}</h2> <button onClick={e => this.increment()}>+</button> {/* Pass a function to a child component that calls this function, */} <CounterButton onClick={e => this.increment()} name="why"/> </div>)} increment() {this.setState({counter: this.state.counter + 1 }) } }Copy the code

Implement slot effect in VUE

import React, { Component } from 'react' export default class App extends Component { render() { return ( <div> <NavBar> <div>aaa</div> <div>bbb</div> <div>ccc</div> </NavBar> <NavBar2 leftSlot={<div>aaa</div>} centerSlot={<div>bbb</div>} RightSlot ={<div> CCC </div>} /> </div>)}} export Default Class NavBar extends Component {render() {//  this.props.children ; return ( <div className="nav-item nav-bar"> <div className="nav-left"> {this.props.children[0]} </div> <div className="nav-item nav-center"> {this.props.children[1]} </div> <div className="nav-item nav-right"> {this.props.children[2]} </div> </div> ) } } export default class NavBar2 extends Component { render() { const {leftSlot, centerSlot, rightSlot} = this.props; return ( <div className="nav-item nav-bar"> <div className="nav-left"> {leftSlot} </div> <div className="nav-item nav-center"> {centerSlot} </div> <div className="nav-item nav-right"> {rightSlot} </div> </div> ) } }Copy the code

Context Application Scenario

Non-parent component data sharing:

  • A more common way to pass data is through the props property from parent to child
  • But there are scenarios where some data needs to be shared among multiple components (locale preferences, UI themes, user login status, user information, and so on).
  • If we define this information in the top-level App and then pass it down, it will be a redundant operation for some components that do not need data in the middle layer.
// Components in the middle layer can pass {... // Use context import React, {Component} from 'React' in the class Component to create a context object, And set the default const UserContext = React. CreateContext ({nickname: 'aaa', level: -1}) class ProfileHeader extends Component {render() {return (<div> <h2> {this.context.nickname}</h2> <h2> {enclosing context. Level} < / h2 > < / div >)}} / / set ProfileHeader contextType ProfileHeader. ContextType = UserContext function Profile (props) {return (< div > < ProfileHeader / >, < ul > < li > set 1 < / li > < li > set 2 < / li > < li > 3 < / li > < li > set 4 < / li > < / ul > < / div > ) } export default class App extends Component { constructor(props) { super(props) this.state = { nickname: 'aaa', level: 99 } } render() { return ( <div> <UserContext.Provider value={this.state}> <Profile /> </UserContext.Provider> </div> ) }} // Use context in a functional component, which can also be used in a class component, And instead of setting the contextType import React for the ProfileHeader, {Component} from 'react' // createContext const UserContext = react. CreateContext ({nickname: 'aaa', level: -1}) function ProfileHeader { Return (< userContext.consumer >{value => {return (<div>{value.nickname value.level}</div> ) } } </UserContext.Consumer> ) } function Profile(props) { return ( <div> <ProfileHeader /> <ul> </li> </li> </li> </li> </li> </li> </li> </li> </li> </li> </li> </li> </div>)} Class App extends Component {constructor() { super() this.state = { nickname: 'aaa', level: 'bbb' } } render() { return ( <UserContext.Provider value={this.state}> <Profile /> </UserContext.Provider> ) } }Copy the code

Why use setState to modify data?

  • React doesn’t know that data has changed if we don’t use setState to modify the data in state. React doesn’t implement a vue3 method to listen for data changes, so we have to use setState to tell React that data has changed and re-render the page

Why is there no method inside the component that implements setState but can be called instead?

  • The reason is simple: the setState method is inherited from Component

SetState Asynchronous update

ChangeText () {this.setstate ({message: 'aaa'}) console.log(this.state.message)Copy the code

Why should setState be asynchronous?

  • SetState is designed to be asynchronous and can significantly improve performance

    • If setState is updated every time, it means that the render function is called frequently and the interface is rerendered, which is inefficient
    • The best approach is to get multiple updates and then batch them
  • If state is synchronized, but the render function has not been executed, then state and props cannot be synchronized

    • The inconsistency between the state and props can cause a lot of problems during development

How do I get the updated value?

// setState takes two arguments: the second argument is a callback function that executes changeText() {this.setstate ({message: 'aaa'}, () = > {the console. The log (this) state) message)})} / / second way: Get componentDidUpdate(prevProps, prevState, snapshot) {console.log(this.state.message)}Copy the code

Is setState necessarily asynchronous?

  • In the component life cycle or React composite event, setState is asynchronous
  • In setTimeout or native DOM events, setState is synchronized
// Update in setTimeout changeText() {setTimeout(() => {this.setState({message: 'aaa' }) console.log(this.state.message) // 'aaa' }, 0)} // Update componentDidMount() {const btnEl = document.getelementById (' BTN ') btnel.adDeventListener ('click', () => { this.setState({ message: 'aaa' }) console.log(this.state.message) // 'aaa' }) }Copy the code

Data consolidation

When modifying a state Object with setState, react internally calls object. assign({}, this.state, the Object passed in setState).

Object.assign(target, … Sources): this method copies only the enumerable properties of the source object to the target object. If the properties in the target object have the same key, the properties will be overwritten by the properties in the source object, and the properties in the later source object will similarly overwrite the properties in the previous source object

SetState itself merges

Increment () {this.setState({counter: this.state.counter + 1}) this.setState({counter: this.state.counter + 1}) this.state.counter + 1 }) this.setState({ counter: This.state.counter + 1})} // Increment () {this.setState((prevState, props) => ({counter: props) prevState.counter + 1 })) this.setState((prevState, props) => ({ counter: prevState.counter + 1 })) this.setState((prevState, props) => ({ counter: prevState.counter + 1 })) }Copy the code

React Update process

The props/state changes — the render function is re-executed — the new DOM number is generated — the old DOM number is diff — the difference is calculated — the DOM number is updated — the real DOM is updated

How old and new DOM trees compare

  • Case 1: Compare different types of elements

    • When an element changes from React, the original tree is removed and a new tree is created
  • Case 2: Compare elements of the same type

    • When comparing two React elements of the same type, React preserves the DOM node and only compares and updates the changed attributes
    • If it is the same type of component elements: component will remain the same, will React to update the component props, and invoke componentWillReceiveProps () and componentWillupdate () method, then calls the render method
  • Case 3: Recurse on child nodes

The optimization of keys

When traversing a list, there is always a warning to add a key property. Adding a unique key allows React to insert or delete lists more efficiently and with better performance

Method of inserting data into a list

  • Method 1: Insert data in the last position

    • In this case, it doesn’t really matter
  • Method 2: Insert data in front

    • In the absence of a key, all items need to be modified
    • When there is a unique key, the item with the key simply needs to be shifted and the new element inserted in front

Precautions for key

  • The key should be unique
  • Do not use a random number for key (random number will regenerate a number in the next render)
  • Using index as the key is not optimized for performance

ShouldComponentUpdate (controls whether the Render method is called or not)

In a nested component, if the parent component’s render function is called, all the child components’ render functions are called again

In fact, many components do not need to rerender. They should call render with the premise that their render function is called when the dependent data (state, props) is changed

React provides a life cycle method shouldComponentUpdate(often referred to as scU for short) that takes arguments and returns values

// Parameter 1: props, the latest props NextState returns a Boolean type true (default), so call render and return false. ShouldComponentUpdate (nextProps, nextState) {if (this.state.counter! == nextState.counter) { return true } return false }Copy the code

PureComponent

If we had to implement shouldComponentUpdate manually for all our classes, that would be a lot more work for us developers

Inheriting the class from PureComponent helps us implement a manual call to shouldComponentUpdate

This method calls shallowEqual, which is a shallow comparison

memo

Class components can be optimized by inheriting from PureComponent, and function components can use the memo higher-order function to achieve the same effect as PureComponent

import React, { memo } from 'react'
const MemoCpn = memo(function Cpn() {
 return (
    <div>memo</div>
 )   
})
Copy the code

The power of immutable data

InsertData () {insertData() {insertData() {insertData() {insertData() { Const newData = {name: "Tom ", age: 30} this.state.friends.push(newData); this.setState({ friends: this.state.friends }); // This method is used to make a shallow copy of a new object, add data to the new object, and then modify the data by setState. Const newFriends = [...this.state.friends]; newFriends.push({ name: "tom", age: 30 }); this.setState({ friends: newFriends }) }Copy the code

Event bus

If there is event passing across components in development, it is passing through the event bus

Yarn add events import {EventEmitter} from 'events' const emiter = new Emitters () emitters () emitters () emitters () emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters () Emitters Listener function)Copy the code

Use the ref

// Add ref import React, {createRef, PureComponent } from 'react' class App extends PureComponent { constructor() { super() this.titleRef = createRef() TitleEl = null} render() {return (<div> <h2 ref={this.titleref}>ref </h2> <h2 ref={e => this.titleel = E}>ref </h2> <button onClick={e => changeText()} </button> </div>)} changeText() {// Enclosing titleRef. Current. InnerHTML = 'object writing this. TitleEl. InnerHTML =' function of writing '}} / / add ref / / ref to function cannot be applied to functional components, because there is no instance, functional components, {PureComponent, forwardRef, callback () {forwardRef, callback (); createRef} from 'react' const Profile = forwardRef(function(props, ref) { return <p ref={ref}>Profile</p> }) class App extends PureComponent { constructor() { super() this.profileRef = createRef() } render() { return ( <div> <Profile ref={this.profileRef} /> </div> ) } }Copy the code

Higher-order Components (HOC)

A higher-order component is a function that takes a component and returns a new component. The Memo function is a higher-order component

The displayName of the component on the browser console can be changed by using the component name.displayname

Portals

In some cases, we want the rendered content to be independent of the parent component, or even of the currently mounted DOM element

Portals provide an excellent solution for rendering child nodes to DOM nodes that exist outside the parent node

import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'
​
class Modal extends PureComponent {
    render() {
        return ReactDom.createPortal(
            this.props.children,
            document.getElementById('#modal')
        )
    }
}
​
class Home extends PureComponent {
  render() {
    return (
      <div>
        <h2>Home</h2>
        <Modal>
          <h2>Title</h2>
        </Modal>
      </div>
    )
  }
}
​
export default class App extends PureComponent {
  render() {
    return (
      <div>
        <Home/>
      </div>
    )
  }
}
Copy the code

fragment

In development, we always wrap a div element when a component returns content, if we don’t want to render the div element

React provides a Fragment phrase: <></> looks like an empty tag, but you can’t use a Fragment phrase if you need to add a key to the Fragment

Strict mode

StrictMode is enabled for components wrapped in <React.StrictMode></React.StrictMode> tags
What does strict mode check for?
  • Identify unsafe lifecycles

  • Use the outdated REF API

  • Use the deprecated findDOMNode method

  • Check for unexpected side effects

    • When strict mode is turned on, the component’s constructor is called twice
    • This is done deliberately in strict mode to let you see if some of the logic written here has any side effects when called multiple times
    • In a production environment, it is not called twice
  • Detect stale context APIS

The React of CSS

Inline style:
  • Inline style is the official recommended way to write CSS styles
  • Style takes a JavaScript object with a small camel named attribute, not a CSS string
  • And you can reference the state in state to set the style

Advantages of inline style:

  • Inline styles do not conflict
  • The state in the current state can be dynamically retrieved

Disadvantages of inline style:

  • All of them require a hump
  • Some styles don’t have prompts
  • Lots of styles, code mess
  • Some styles cannot be written (such as pseudo-classes/pseudo-elements)
// inline style import React, { PureComponent } from 'react' class App extends PureComponent { constructor() { super() this.state = { color: 'pink' } } render() { const pStyle = { color: this.state.color, textDecoration: 'underline' } return ( <div> <h2 style={{fontSize: '20px', color: 'red'}}></h2> <p style={pStyle}></p> </div> ) } }Copy the code
Common CSS
  • Normal CSS is usually written in a separate file and then introduced
  • In componentized development, we always want components to be independent modules, and even styles to work within themselves and not affect each other
  • But normal CSS is global CSS, and styles affect each other

CSS Modules (fixes local scope issues)

CSS modules are not a React specific solution, but can be used in any environment that uses a webPack-like configuration

React scaffolding is already configured with CSS Modules

The disadvantage of cssmodule

  • The referenced class name cannot be used with a hyphen (.home-title), and is always unreadable in JavaScript
  • All classnames must be written in the {style.className} form
  • It is not convenient to change some styles dynamically, so you still need to use inline styles
Import style from './style.modules. CSS 'export default class Profile extends PureComponent { constructor(props) { super(props); this.state = { color: "purple" } } render() { return ( <div className="profile"> <h2 className={style.title} style={{color: This.state. color}}> I am the title of the Profile </h2> <ul className={style. Settings}> <li className={style.settingItem}> Set list 1</li> <li> Set list 2</li> <li> Set list 3</li> </ul> </div>)}}Copy the code
css in js
  • “Css in JS” refers to a pattern in which Css is generated by JavaScript rather than defined in external files
  • Note that this feature is not part of React, but is provided by a third-party library

Currently more popular Css in JS library

  • styled-components
  • emotion
  • glamorous

Styled – Components (implemented via the ES6 tag template string)

  • Install styled- Components yarn add styled- Components
import styled from 'styled-components' const CFInput = styled.input.arrts({ placeholder: 'cf', })` color: red; border-color: ${props => props. BColor} '<CFInput bColor='red' /> / Const Input2 = Styled (CFInput) ' '// Support for nesting // Styled Settings main import {ThemeProvider} from' property-Components'  <ThemeProvider theme={{color: 'red', fontSize: '30px'}}> <Home></Home> </ThemeProvider>Copy the code

Modify the React WebPack configuration

  • You can use YARN Run eject to expose the configuration information and modify it
  • But for those unfamiliar with WebPack, direct modification is not good
Craco
  • Install craco YARN add@craco/Craco
  • Change package.json file from react-scripts to craco

  • Create craco.config.js in the root directory to modify the default configuration
Module. exports = {webapck: {alias" {// config.js module. Exports = {webapck: {alias" {// config.js module.Copy the code

Redux

Pure functions

  • Being certain of the input must produce certain of the output
  • No side effects during execution (modifying parameters, etc.)

React requires that either a function or a class declare a component, which must act like pure functions and protect their props from modification

Redux is a container that helps us manage State: Redux is a JavaScript State container that provides predictable State management

The core concept of Redux
  • store

  • Action: Redux asks us to update the data through action

    • All data changes must be updated through dispatch actions
    • Action is a plain JavaScript object that describes the type and content of the update
    • The advantage of enforcing actions is that you can clearly see what changes have taken place in the data. Are all data changes traceable
How to use Redux
  • Create an object as the state we want to save

  • Create a store to store this state

    • Reducer must be created when creating a store
    • The current state can be obtained by using store.getState
  • Modify state with action

    • Dispatch actions via Dispatch
    • Actions usually have a type attribute and can carry other data as well
  • Modify the process code in the Reducer

    • It is important to note here that Reducer is a pure function and does not need to modify state directly
//yarn add redux import {createStore} from 'redux' const defaultState = {num: 0 } const store = createStore(reducer) function reducer(state = defaultState, action) { switch (action.type) { case 'add1': case 'add2': return { ... State, num: action.num} default: return state}} Action2 = state = > ({type: 'add2', num: store.getState(). Num + 1}) const action2 = state = > ({type: 'add2', num: Subscribe (() => {console.log('num:' + store.getstate ().num); }) store.dispatch(action1) store,dispatch(action2(store.getStore))Copy the code
Customize connect function for react-redux
// Create a context object import React from 'React '; const StoreContext = React.createContext(); Import {StoreContext} from './utils/context' import store from '.... ' ReactDOM.render( <StoreContext.Provider value={store}> <App /> </StoreContext.Provider>, document.getElementById('root') ); // connect function import React, {PureComponent} from "React "; import { StoreContext } from './context'; export function connect(mapStateToProps, mapDispachToProp) { return function enhanceHOC(WrappedComponent) { class EnhanceComponent extends PureComponent { constructor(props, context) { super(props, context); this.state = { storeState: mapStateToProps(context.getState()) } } componentDidMount() { this.unsubscribe = this.context.subscribe(() => { this.setState({ storeState: mapStateToProps(this.context.getState()) }) }) } componentWillUnmount() { this.unsubscribe(); } render() { return <WrappedComponent {... this.props} {... mapStateToProps(this.context.getState())} {... mapDispachToProp(this.context.dispatch)} /> } } EnhanceComponent.contextType = StoreContext; return EnhanceComponent; }}Copy the code
The use of the react – story
  • Install react-redux yarn add react-redux

    Import {connect} from 'react-redux' export default connect(mapStateToProps, MapDispatchToProps)(Home) // in index.js import {Provider} from 'react-redux' import {Store} from './ Store ' ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )Copy the code
redux-thunk
  • In the previous simple case, redux saved counter as locally defined data
  • But in real development, a lot of the data that Redux stores might come from the server, and we would need to make asynchronous requests and save the data to Redux
  • We can put the asynchronous code for the network request into the lifecycle of the component, wait until the data is returned, and then store the data in redux
  • In fact, the network request data is part of our state management, and a better approach would be to hand over the asynchronous code to Redux as well
How can asynchronous operations be performed in REdux?
  • Using middleware
  • The purpose of this middleware is to extend some of its own code between the actions at dispatch and the final reducer
  • All we have to do here is send an asynchronous network request
How do I use redux-thunk
  1. Install redux-thunk yarn add redux-thunk

  2. The Enhance function of Middleware is passed in when a store is created

    • Returns an enhancer by combining multiple Middleware with applyMiddleware
    • Pass enhancer as the second parameter to createStore
    • import { applyMiddleware } from 'redux'
      import thunkMiddleware from 'redux-thunk'
      const storeEnhancer = applyMiddleware(thunkMiddleware)
      const store = createStore(reducer, storeEnhancer)
      ​
      Copy the code
  3. Defines an action that returns a function

    • Note: this is not returning an object, but a function
    • This function will be executed after dispatch
    • Const action = (dispatch, getState) => {// Make an asynchronous operation here // Save data to redux via Dispatch when the asynchronous operation results return}Copy the code
redux-devtools

Redux makes it easy to track and debug state, so how?

  • The redux-DevTools tool is available on the redux website. You can use this tool to know how the state is changed each time, and how the state changes before and after the modification, etc

Steps to install the tool:

  1. Install the related plug-in redux-devTools in your browser

  2. Inherit devTools middleware in Redux

    import { createStore, applyMiddleware, compose } from 'redux';
    const composeEnhancers = 
          window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;
    const storeEnhancer = applyMiddleware(thunkMiddleware, sagaMiddleware);
    const store = createStore(reducer, composeEnhancers(storeEnhancer));
    Copy the code
redux-sage

Redux-saga is another middleware used to send asynchronous requests on Redux, which is more flexible to use.

Reducer of the split

In a project, we will have multiple pages. If we manage the status of multiple pages in a Reducer, with the huge project, it will inevitably lead to bloated code and difficult to maintain. Therefore, we need to split the reducer

Redux provides a combineReducers function that merges multiple reducers into a reducer

import {combineReducers} from 'redux'
​
import { reducer as counterReducer } from './counter';
import { reducer as homeReducer } from './home';
​
const reducer = combinereducers({
    counterInfo: counterReducer,
    homeInfo: homeReducer
})
Copy the code

react-router

Install the react – the router:

  • Installing the react-router-dom will automatically help us install the react-router dependencies
  • yarn add react-router-dom
Basic use of Router

The main API of the React-Router is a set of components provided to us

  • BrowserRouter or HashRouter

    • The Router contains listening for path changes and passes the corresponding paths to the child components
    • BrowserRouter uses history mode
    • HashRouter use
  • The Link and NavLink

    • Usually a jump to a path uses a Link component, which is eventually rendered as an A element

    • NavLink adds style properties to Link: By default, NavLink components add a class when the path is selected, the class name can be changed using the activeClassName property, and a CSS object modification style can be passed to the activeStyle property

      To property: The most important property in Link, used to set the path to jump to

  • Route

    • Route Is used to match paths
    • Path property: Sets the path to be matched
    • Component property: Sets the component to render after the path is matched
    • Exact: indicates exact matching. Components are rendered only when the exact matching path is the same
import { BrowserRouter, Route, Link } from 'react-router-dom' import Home from './home' import About from './about' import Profile from './profile' // Render () {return (<BrowserRouter> <Link to='/'> home </Link> <Link to='/about'> about </Link> </Link> <Link To ='profile'> my </Link> <Route exact path='/' Component ={Home} /> <Route path='/about' component={about} /> <Route path='/profile' component={Profile} /> </BrowserRouter> ) }Copy the code
The role of the Switch

By default, the component will be rendered whenever the path matches, but in practice you want to have an exclusive idea that once you match the first one, the rest should not match, and wrap the Route tag around the component

Parameters of the problem

Check react Note 2

Manual hop route

The history object must be obtained to route to a manual redirect

How can I get the history object?

  • If the component is routed directly to it, then you can get the History, location, and match objects directly from props
  • If the component is a normal rendered component, wrap the withRouter(App) with a higher-order component, withRouter
react-router-config
  • So far all of our Route definitions are done directly using the Route component and adding attributes
  • However, this approach can become very confusing, and we want to centralize all routing configurations in one place
  • Yarn add react-router-config install yarn add react-router-config
  • Configure a relational array of route mappings
  • Use the renderRoutes function to complete the configuration
Import {Redirect} from 'react-router-dom' const routes = [{path: '/', exact: true, render: () => (// Redirect to='/home' />)}, {path: '/about', Component: about, routes: [// child routes]}] export default routes import {renderRoutes} from 'react-router-config' import routes from App './router' render() { return ( { renderRoutes(routes) } ) }Copy the code

React Hooks

Briefly summarize Hook:
  • It allows us to use state and other React features without writing a class
Usage scenarios of Hook:
  • The advent of hooks has replaced almost all of our previous use of class components (except for some very unusual scenarios).
  • If it’s an old project, you don’t need to refactor all the code because it’s fully backward compatible and can be used incrementally
  • Hooks can only be used in functional components, not outside of functional components
  • A Hook can only be called from the outermost layer of a function, not from a loop, a conditional judgment, or a subfunction
useState
Import {useState} from 'react' // The first argument is the variable, the second argument is the method to modify the variable, it receives a new state value, Const [variable name, set variable name] = useState() // Default values can be added in parenthesesCopy the code

Unlike setState in the Class component, useState does not automatically merge update objects. The effect of merging updated objects can be achieved by using a functional setState in conjunction with the expansion operator

const [state, setState] = useState({}) setState((prevState) => { return {... prevState, ... updateValues} })Copy the code
useEffect

We can pass a callback parameter in the useEffect function, which will be called when react renders to a certain stage. We can make network requests in the useEffect function, manually update the DOM, and listen for some events

UseEffect (() => {console.log(" subscribe to some events ")); Return () => {console.log(" unsubscribe event ")}});Copy the code

Use multiple Useeffects: useEffect hooks can be used multiple times to perform different operations on different useeffects, executing the code in the same order as writing the code

Effect performance optimization: by default, the useEffect callback is reexecuted on every render, but sometimes we only want it to be executed once, or when some data changes. This can be determined by using the second parameter of useEffect

UseEffect (() => {console.log(" change DOM", count); }, [count]); UseEffect (() => {console.log(" subscribe to events "); } []); UseEffect (() => {console.log(" network request "); } []); // It is executed only once when the component is first enteredCopy the code
useContext

In previous development, we used a shared Context in components in two ways

  • A class component can retrieve the context from the class by contextType = MyContext
  • Multiple contexts or shared contexts in functional components via myContext.consumer
Const user = useContext(UserContext); // The argument must be the context created by createContext() const theme = useContext(ThemeContext);Copy the code
useReducer

UseReducer is simply an alternative to useState:

  • In some scenarios, if the processing logic of state is complicated, we can use useReducer to split it

  • Or this modification needs to rely on the previous state, which can also be used

    const initialState = {count: 0};
    ​
    function reducer(state, action) {
      switch (action.type) {
        case 'increment':
          return {count: state.count + 1};
        case 'decrement':
          return {count: state.count - 1};
        default:
          throw new Error();
      }
    }
    ​
    function Counter() {
      const [state, dispatch] = useReducer(reducer, initialState);
      return (
        <>
          Count: {state.count}
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
        </>
      );
    }
    Copy the code
useCallback

The actual purpose of useCallback is to optimize performance

How to optimize performance?

  • UseCallback returns the memoized value of a function
  • In the case of invariant dependencies, the same value is returned multiple times when the definition is repeated
Const increment2 = useCallback(() => {console.log(" execute increment2 function "); setCount(count + 1); }, [count]);Copy the code

The general purpose of using useCallback is not to render child components more than once, but not to cache functions.

When a parent component passes a function to a child component, using the function returned by useCallbac allows the component to render less.

useMemo

The actual purpose of useMemo is also for performance optimization

How to optimize performance?

  • UseMemo also returns a Memoized value
  • In the case of invariant dependencies, the same value is returned multiple times when the definition is repeated
Import React, {useState, useMemo} from 'React '; Function calcNumber(count) {console.log("calcNumber recalculated "); let total = 0; for (let i = 1; i <= count; i++) { total += i; } return total; } export default function MemoHookDemo01() { const [count, setCount] = useState(10); const [show, setShow] = useState(true); // const total = calcNumber(count); Const total = useMemo(() => {return calcNumber(count) is recalculated only when count changes; }, [count]); Return (<div> <h2> computes the sum of numbers: {total}</h2> <button onClick={e => setCount(count + 1)}>+1</button> <button onClick={e => setShow(! </button> </div>)}Copy the code
Import React, {useState, memo, useMemo} from 'React '; import React, {useState, memo, useMemo} from' React '; Const HYInfo = memo((props) => {console.log("HYInfo re-render "); Return <h2> name: {props.info.name} age: {props.info.age}</h2>}); Export default function MemoHookDemo02() {console.log("MemoHookDemo02 "); const [show, setShow] = useState(true); //const info = { name: "why", age: 18 }; Const info = useMemo(() => {// Const info = useMemo() => {// Const info = useMemo() => {// Const info = useMemo() => {name: "why", age: 18 }; } []); return ( <div> <HYInfo info={info} /> <button onClick={e => setShow(! </button> </div>)}Copy the code
useRef

UseRef returns a REF object that remains constant throughout the life of the component

The most common refs are used in two ways:

  • Usage 1: Introduce DOM (or component, but class component) elements
  • Usage two: Save a data, how long can this object lifetime remain unchanged
// DOM class TestCpn extends React.Component {render() {return <h2>TestCpn</h2>} TestCpn2 = forwardRef(function TestCpn2(props, ref) { return <h2 ref={ref}>TestCpn2</h2> }) export default function RefHookDemo01() { const titleRef = useRef(); const inputRef = useRef(); const testRef = useRef(); const testRef2 = useRef(); function changeDOM() { titleRef.current.innerHTML = "Hello World"; inputRef.current.focus(); console.log(testRef.current); console.log(testRef2.current); } return ( <div> <h2 ref={titleRef}>RefHookDemo01</h2> <input ref={inputRef} type="text"/> <TestCpn ref={testRef}/> <TestCpn2 ref={testRef2}/> <button onClick={e => changeDOM()}> </button> </div>)}Copy the code
Export default function RefHookDemo02() {const [count, setCount] = useState(0); const numRef = useRef(count); console.log(numRef.current); useEffect(() => { numRef.current = count; }, [count]) return (<div> {/* <h2>numRef: {numRef. Current}</h2> <h2>count: {count}</h2> */} <h2>count <button onClick={e => setCount(count +10)}>+10</button> </div>)}Copy the code
useImperativehandle
Import React, {useRef, forwardRef, useImperativehandle} from 'React '; const CFInput = forwardRef((props, ref) => { const inputRef = useRef() useImperativeHandle(ref, () => { focus: () => { inputRef.current.focus() } }, [inputRef]) return <input ref={inputRef} type='text'></input> }) function UseImperativeHandleHookDemo() { const inputRef  = useRef(); Return (<div> <HYInput ref={inputRef}/> <button onClick={e => inputref.current. Focus ()}> focus </button> </div>)}Copy the code
useLayoutEffect

UseLayoutEffect and useEffect are very similar, in fact there is only one difference

  • UseEffect is executed after the rendered content is updated to the DOM and does not block DOM updates
  • UseLayoutEffect is executed before rendering content is updated to the DOM, blocking updates to the DOM
import React, { useState, useEffect } from 'react' export default function EffectCounterDemo() { const [count, setCount] = useState(10); UseEffect (() => {if (count === 0) {setCount(math.random () + 200)}}, [count]); UseLayoutEffect (() => {if (count === 0) {setCount(math.random () + 200)}}, [count]); <button onClick={e => setCount(0)}> </div>)}Copy the code

redux-hook

UseSelector is used to map state to the component
Import {useSelector, shallowEqual, useDispatch} from 'react-redux' const {useSelector} = useSelector(state => ({useSelector: }), shallowEqual) // shallowEqual for shallow comparisons, Performance optimization const dispatch = useDispatch() // Dispatch can be used to dispatch actionsCopy the code

immutable js

  • When redux processes data, it is possible to use IMMUTABLE JS to improve data processing by making shallow copies of objects each time, which may affect performance
  • Immutable js 官网 :immutable-js.com/