When we use React to develop, the actual use of react API is very few, basically stay in the Component, react. Memo level, the actual React source code, exposed methods are not many, but we rarely use. But it’s not useless that React exposes so many apis. If you want to play React, you need to understand what these apis are for and what their application scenarios are.

Instead of reading the official documents, this article will use a small demo to demonstrate most of the APIS, from class components, life cycle, function components, hooks, tool components to react-dom, in order to make it easier for you to understand.

Class components and function components

Component Class and how it works

Create a class component

use

<B />

The thinking of the react

For Component, react processing logic is quite simple. We instantiate the Component of our class, and then assign an Updater object that is responsible for updating the Component. Then, in each phase of the component, execute the class component’s render function, and the corresponding lifecycle function is ok.

function Component(props, context, updater) { this.props = props; this.context = context; this.refs = emptyObject; this.updater = updater || ReactNoopUpdateQueue; } function constructClassInstance( workInProgress, ctor, props ){ const instance = new ctor(props, context); Instance.updater = {isMounted, enqueueSetState(){/* setState (), enqueueReplaceState(){}, EnqueueForceUpdate (){/* forceUpdate triggers logic here */}}}Copy the code

State Internal data

The setState class component does not immediately change this.state

The solution is to use a callback function or a functional expression

Props Indicates a common method for communicating external data between components

The child element gets the value of the parent element using props or Instance Methods

Parent app.js:

import React,{ Component } from "react"; import Sub from "./SubComponent.js"; Export Default class App extends Component{render(){return(<div> <Sub title = "" /> </div>)}}Copy the code

Subcomponent.js:

import React from "react";

const Sub = (props) => {
    return(
        <h1>
            { props.title }
        </h1>
    )
}

export default Sub;
Copy the code

A child element is passed to the parent element by calling the parent element’s Callback Functions

SubComponent. Js:

import React from "react"; const Sub = (props) => { const cb = (msg) => { return () => { props.callback(msg) } } return( <div> <button onClick = { Cb (" let's communicate ")}> click on me </button> </div>)} export default Sub;Copy the code

App. Js:

import React,{ Component } from "react";
import Sub from "./SubComponent.js";

export default class App extends Component{
    callback(msg){
        console.log(msg);
    }
    render(){
        return(
            <div>
                <Sub callback = { this.callback } />
            </div>
        )
    }
}
Copy the code

Communication between brothers can be mediated by the parent element

Other common communication methods for unrelated components include Portals, Redux, and useContext, as described below

The life cycle

React life cycle, with common components in green

constructor

  • Basic uses:

Initialize the props

Initialize state, but setState cannot be called at this time

Use to write bind this

shoudComponentUpdate

  • use

Return true to not block UI updates

Returns false to prevent UI updates

We can manually determine whether to update based on the return value set for the reference scenario, avoiding unnecessary updates

Suppose the operation data does not change in the end as follows

We type ‘render’ in render and the discovery appears twice

At this point we need shoudComponentUpdate

Unnecessary updates are blocked

This functionality was eventually built into the React.PureComponent component

The use of PureComponent is similar to that of Component. The only difference is that PureComponent is lighter than PureComponent. (3) compare each key of the new and old props and each key of the new and old props before render. If all key values are the same, it will not render; Render if any of the key values are different. Therefore, it is generally used for performance tuning to reduce render times.

render

  • use

Display view return(

)

There’s only one root element

For two root elements, use

… < / React. Fragments > or < >… < / a > package

Note: Unlike fragments, fragments can support the key attribute. <></> The key attribute is not supported.

componentDidMount

  • use

Code that depends on the DOM is executed after the element is inserted into the page

For example, if we want to get the height of a div, we’d better do it inside this component

This is where you can make an AJAX request to load the data (official recommendation)

The hook is executed for the first rendering

componentDidUpdate

  • use

Execute the code after the view has been updated

AJAX requests can also be made here to update the data

This hook is not executed for the first rendering

SetState may cause a wireless loop at this point, and can be put in if to determine how to break out of the loop

This hook is not fired if shouldComponentUpdate returns false

componentWillUnmount

  • use

Execute code when the component is about to be removed from the page and then destroyed

Unmounted components cannot be mounted again

  • For example,

1. In the c… If we listened on Window Scroll in DidMount, we’ll unlisten on componentWillUnmount

2. In the c… So if you created a Timer in DidMount, you’re going to cancel the Timer in componentWillUnmount

3. In the c… If you made an AJAX request in DidMount, you cancel the request in componentWillUnmount

Principle: who pollution who governance, otherwise will occupy memory

Look at the hook execution sequence in stages

The react function component

Implement +1 operations and class component comparisons

The class components

Function component

Function components replace class components

UseState instead of setState

UseEffect instead of life cycle

Hooks take each one out

Implement useState

As shown in the example above, the order of index is very important, and react does not allow if cases:

This will cause an error in the index order:

conclusion

Note: setState does not immediately change state

The use of usesState

A shallow copy is required to partially update:

useReducer

The first argument that useReducer accepts is a function, We can think of it as a reducer, where the parameters are the state and action in the regular reducer, and the reducer returns the changed state. UseReducer’s second parameter is the initial value of state and returns an array. The first item in the array is the value of state after the update, and the second argument is the dispatch function that dispatches the update.

The contents of the Dispatch are passed to the Action

useContext

useEffect

Encapsulation useEffect (() = > {}, [n])

When useEffect(()=>{},[n]) is used, a conflict with the initial value of useState will reset the value of state once, causing unknown risks. We need to filter the initial value the first time.

useLayoutEffect

UseEffect is executed after the browser rendering is complete

UseLayoutEffect is executed before the browser renders

UseEffect can be used as an event listener, as well as some DOM-based operations. Don’t forget to use the first argument of the useEffect callback function, return a function to clear the event listener and so on.

Const DemoEffect =({a}) =>{/* Const handleResize =()=>{} useEffect(()=>{/* Timer timer, etc. */ const Timer = SetInterval (()=>console.log(666),1000) /* Event listener */ window.addeventListener ('resize', HandleResize) / * * this function is used to remove side effects/return function () {clearInterval (timer) window. RemoveEventListener (' resize, handleResize) } },[ a ]) return (<div > </div>) }Copy the code

useMemo

memo

Memo avoids loading child when the data is not changing. If not, the above two lines of log will be printed

References to external functions in the app in the child

And then we see that when n changes, the child also loads. This is due to the fact that the new and old functions have the same function but not the same address, triggering a reload of the child

Solution: useMemo

UseMemo takes two arguments. The first argument is a function that returns the value used to produce the save value. The second argument is an array of dep dependencies. The dependencies in the array are changed, and the first function is executed again, producing a new value.

useCallback

useRef

When useRef is created, the original object is created, and the original object will remain as long as the function component is not destroyed, so we can use this feature to save some data (labels or form components) through useRef.

Note: When count. Current changes, the value in the DOM changes, but render does not update the view

Can useRef render automatically

Just use useState to change the value of state each time count. Current changes

forwardRef

UseRef can also refer to dom objects, using ref= the object you named. The advantage of this is that you don’t need an ID or class to find the tag

ForwardRef allows button3 to accept a second parameter, ref={ref}, to reference the DOM object within the component

UseImperativeHandle Custom ref

UseImperativeHandle can customize the instance value exposed to the parent component in conjunction with the forwardRef. This is useful, because we know that for a child component, if it’s a class component, we can get an instance of that class component by ref, but in the case of a function component, if we can’t get an instance of that class component directly by ref, In this case, useImperativeHandle and forwardRef can cooperate to achieve the effect.

UseImperativeHandle accepts three parameters:

The first parameter ref: accepts the ref passed by the forWardRef.

The second argument, createHandle: the handler function, returns the value as the REF object exposed to the parent.

The third parameter deps: the dependency deps, which changes to form the new REF object.

Example of removing a button

Simple custom hooks

Expose the read and delete interfaces

Using an interface

Use hooks to avoid stale closure example

Utility class

React. Lazy and Suspense implement lazy loading

React. Lazy is used with Suspense to dynamically load components. React. Lazy accepts a function that requires a dynamic call to import(). It must return a Promise that resolves a Default export React component.

The parent component

import Index from './test' const LazyComponent = React.lazy(()=> new Promise((resolve)=>{ setTimeout(()=>{ resolve({ default: ()=> <Index /> }) },2000) })) render(){ return ( <div className="App"> <div className="context_box" style={ { marginTop Suspense ={<div className="icon" > </div>} > <LazyComponent /> </React.Suspense> </div> </div> ); }Copy the code

Child components

import React from "react"; Class Index extends React.Com {constructor(props) {super(props)} render() {return (<div> -- </div>)} } export default IndexCopy the code

Profiler performance overhead tests

The Profiler API is used to detect the performance overhead of a react component during the development phase.

Profiler requires two parameters:

The first argument, which is the id, is used to identify the unique Profiler.

The second parameter: the onRender callback function, which is used for rendering to complete, accepts render parameters.

const index = () => { const callback = (... arg) => console.log(arg) return <div > <div > <Profiler id="root" onRender={ callback } > <Router > <Meuns/> <KeepaliveRouterSwitch withoutRoute > { renderRoutes(menusList) } </KeepaliveRouterSwitch> </Router> </Profiler> </div> </div> }Copy the code

The results of

  • 0-id: root -> ID of the Profiler tree.
  • 1-phase: mount -> mount, update has rendered.
  • 2-actualDuration: 6.685000262223184 -> The committed render time to update.
  • 3-baseduration: 4.430000321008265 -> The time required to render the entire subtree
  • 4 -startTime: 689.7299999836832 -> Start rendering time for this update
  • 5 -commitTime: 698.5799999674782 -> commitTime: 698.57999674782 -> Committed time
  • 6 – Interactions: set{} -> Set of interactions for this update

StrictMode indicates the StrictMode

StrictMode is used to detect potential problems in the React project. Like Fragment, StrictMode does not render any visible UI. It triggers additional checks and warnings for its descendant elements.

Strict mode checks run only in development mode; They do not affect the production build, only trigger warnings.

StrictMode currently helps:

① Identify the life cycle of insecurity.

② Warning about using the outdated string REF API

③ Warning about using obsolete findDOMNode methods

(4) Detect unintended side effects

⑤ Detect outdated context API

Enable strict mode:

<React.StrictMode> 
   ...
</React.StrictMode>
Copy the code

createElement

When we talk about createElement, we can’t help but associate it with JSX. The JSX that we write will eventually be Babel compiled as a React element using createElement.

Such as:

Render (){return <div className="box" > <div className="item" >Copy the code

Be interpreted as:

React.createElement("div", {
  className: "box"
}, React.createElement("div", {
  className: "item"
}, "\u751F\u547D\u5468\u671F"));
Copy the code

Babel online parsing

Model of createElement:

React.createElement(
  type,
  [props],
  [...children]
)
Copy the code

The first argument: if it’s a component type, it passes the component; if it’s a DOM element type, it passes a string like div or span.

Second argument: The second argument is an object, which is a property in the DOM type and props in the component type.

Other parameters: children

cloneElement

CloneElement is used to clone and return a new React element from the Element template.

We can hijack the Children Element in the component, and then clone the element with cloneElement to interfuse props. The classic example is the Swtich component in the React-Router, which matches unique routes and renders them in this way.

We set up a scenario, in the component, to hijack the children, and then empower the children with some extra props:

function FatherComponent({ children }){
    const newChildren = React.cloneElement(children, { age: 18})
    return <div> { newChildren } </div>
}

function SonComponent(props){
    console.log(props)
    return <div>hello,world</div>
}

class Index extends React.Component{    
    render(){      
        return <div className="box" >
            <FatherComponent>
                <SonComponent name="alien"  />
            </FatherComponent>
        </div>   
    }
}
Copy the code

createContext

CreateContext is used to create a Context object. The createContext object contains the Provider that passes the value of the Context object, and the Consumer that receives subscriptions to changes in the value.

const MyContext = React.createContext(defaultValue)

CreateContext takes a parameter defaultValue and applies it as value if the Consumer never had a Provider. The defaultValue parameter takes effect only if there is no Provider match in the component’s tree.

Function ComponentB(){function ComponentB(){ */ return < myContext.consumer > {(value) => <ComponentA {... Function (props){const {name, mes} = props return <div> <div> {name} </div> <div>  { mes } </div> </div> } function index(){ const [ value , ] = React.useState({ name:'alien', mes:'let us learn React ' }) return <div style={{ marginTop:'50px' }} > <MyContext.Provider value={value} > <ComponentB /> </MyContext.Provider> </div> }Copy the code

Print result:

createRef

CreateRef creates a ref element attached to the React element.

Usage:

class Index extends React.Component{
    constructor(props){
        super(props)
        this.node = React.createRef()
    }
    componentDidMount(){
        console.log(this.node)
    }
    render(){
        return <div ref={this.node} > my name is alien </div>
    }
}
Copy the code

Function component

function Index(){ const node = React.useRef(null) useEffect(()=>{ console.log(node.current) },[]) return <div ref={node}  > my name is alien </div> }Copy the code

isValidElement

This method can be used to detect if it is a React Element, accepting the object to be validated, and returning true or false.

This API may not be useful for business component development, because the internal state of the component is known, and we do not need to verify whether it is a React Element. However, for common components or open source libraries, isValidElement is useful.

Before validation with isValidElement:

const Text = () => <div>hello,world</div> 
class WarpComponent extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return this.props.children
    }
}
function Index(){
    return <div style={{ marginTop:'50px' }} >
        <WarpComponent>
            <Text/>
            <div> my name is alien </div>
            Let's learn react together!
        </WarpComponent>
    </div>
}
Copy the code

We use isValidElement for react Element validation:

class WarpComponent extends React.Component{
    constructor(props){
        super(props)
        this.newChidren = this.props.children.filter(item => React.isValidElement(item) )
    }
    render(){
        return this.newChidren
    }
}
Copy the code

Children.map

React.Children provides a practical method for handling this.props. Children’s opaque data structure.

If you want to iterate over children, don’t you just use an array,map, forEach? Let’s take a look at an opaque data structure. What is an opaque structure?

Let’s first look at the structure of transparency:

class Text extends React.Component{
    render(){
        return <div>hello,world</div>
    }
}
function WarpComponent(props){
    console.log(props.children)
    return props.children
}
function Index(){
    return <div style={{ marginTop:'50px' }} >
        <WarpComponent>
            <Text/>
            <Text/>
            <Text/>
            <span>hello,world</span>
        </WarpComponent>
    </div>
}
Copy the code

But let’s change the Index structure:

function Index(){
    return <div style={{ marginTop:'50px' }} >
        <WarpComponent>
            { new Array(3).fill(0).map(()=><Text/>) }
            <span>hello,world</span>
        </WarpComponent>
    </div>
}
Copy the code

This data structure, we’re not going to be able to traverse it properly, and even if we do, we’re not going to be able to traverse every child element. That’s where React.Chidren comes in.

Let’s treat the children with the WarpComponent using React.Chidren:

function WarpComponent(props){
    const newChildren = React.Children.map(props.children,(item)=>item)
    console.log(newChildren)
    return newChildren
}
Copy the code

Note that if children is a Fragment object, it will be treated as if it were a single child node and will not be traversed.

Children.forEach

ForEach is used similarly to children.map, children.map returns a new array, and children.foreach stays in the traversal phase.

Children.count

The total number of components in children is equal to the number of times the callback function was called from map or forEach. For more complex results, children.count can return the number of Children at the same level.

function WarpComponent(props){
    const childrenCount =  React.Children.count(props.children)
    console.log(childrenCount,'childrenCount')
    return props.children
}   
function Index(){
    return <div style={{ marginTop:'50px' }} >
        <WarpComponent>
            { new Array(3).fill(0).map((item,index) => new Array(2).fill(1).map((item,index1)=><Text key={index+index1} />)) }
            <span>hello,world</span>
        </WarpComponent>
    </div>
}
Copy the code

Children.toArray

Children.toArray Returns, props. Children flattening result.

function WarpComponent(props){
    const newChidrenArray =  React.Children.toArray(props.children)
    console.log(newChidrenArray,'newChidrenArray')
    return newChidrenArray
}   
function Index(){
    return <div style={{ marginTop:'50px' }} >
        <WarpComponent>
            { new Array(3).fill(0).map((item,index)=>new Array(2).fill(1).map((item,index1)=><Text key={index+index1} />)) }
            <span>hello,world</span>
        </WarpComponent>
    </div>
}
Copy the code

Children.only

Verify that children has only one child (a React element) and return it if so, otherwise this method throws an error.

function WarpComponent(props){
    console.log(React.Children.only(props.children))
    return props.children
}   
function Index(){
    return <div style={{ marginTop:'50px' }} >
        <WarpComponent>
            { new Array(3).fill(0).map((item,index)=><Text key={index} />) }
            <span>hello,world</span>
        </WarpComponent>
    </div>
}
Copy the code

Tool components are referencedThe React advanced, the author summed up very comprehensively

react-dom

render

Render is our most commonly used REact-DOM API. It is used to render a react element. We usually use it for react projects.

ReactDOM.render(element, container[, callback])

Use:

ReactDOM.render(
    < App / >,
    document.getElementById('app')
)
Copy the code

hydrate

Server render with hydrate. The use is the same as render(), but it is used to hydrate the content of HTML in the container rendered by the ReactDOMServer. ReactDOM.hydrate(element, container[, callback])

createPortal

Portal provides an excellent solution for rendering child nodes to DOM nodes that exist outside the parent component. CreatePortal can render the child nodes of the current component or element outside of the component.

So what scenario does it apply to?

For example, some global popover components, such as the Model, are written inside our component, but the real dom is mounted in the outer container, such as the body. This is where the createPortalAPI fits nicely.

CreatePortal takes two arguments:

ReactDOM.createPortal(child, container)

The first: Child is any renderable React child. The second: Container is a DOM element.

function WrapComponent({ children }){
    const domRef = useRef(null)
    const [ PortalComponent, setPortalComponent ] = useState(null)
    React.useEffect(()=>{
        setPortalComponent( ReactDOM.createPortal(children,domRef.current) )
    },[])
    return <div> 
        <div className="container" ref={ domRef } ></div>
        { PortalComponent }
     </div>
}

class Index extends React.Component{
    render(){
        return <div style={{ marginTop:'50px' }} >
             <WrapComponent>
               <div  >hello,world</div>
            </WrapComponent>
        </div>
    }
}
Copy the code

unstable_batchedUpdates

In react-Legacy mode, react events can be batch updated to handle events, but the batch update function will be broken for non-routine events. So we can use the React-DOM unstable_batchedUpdates for batch updates.

One-click batch updates

class Index extends React.Component{
    constructor(props){
       super(props)
       this.state={
           numer:1,
       }
    }
    handerClick=()=>{
        this.setState({ numer : this.state.numer + 1 })
        console.log(this.state.numer)
        this.setState({ numer : this.state.numer + 1 })
        console.log(this.state.numer)
        this.setState({ numer : this.state.numer + 1 })
        console.log(this.state.numer)
    }
    render(){
        return <div  style={{ marginTop:'50px' }} > 
            <button onClick={ this.handerClick } >click me</button>
        </div>
    }
}
Copy the code

The batch update condition was broken. Procedure

 handerClick=()=>{
    Promise.resolve().then(()=>{
        this.setState({ numer : this.state.numer + 1 })
        console.log(this.state.numer)
        this.setState({ numer : this.state.numer + 1 })
        console.log(this.state.numer)
        this.setState({ numer : this.state.numer + 1 })
        console.log(this.state.numer)
    })
  }
Copy the code

Unstable_batchedUpdate power

handerClick=()=>{
        Promise.resolve().then(()=>{
            ReactDOM.unstable_batchedUpdates(()=>{
                this.setState({ numer : this.state.numer + 1 })
                console.log(this.state.numer)
                this.setState({ numer : this.state.numer + 1 })
                console.log(this.state.numer)
                this.setState({ numer : this.state.numer + 1 })
                console.log(this.state.numer)
            }) 
        })
    }
Copy the code

Render times once, perfect for batch updates.

flushSync

FlushSync can place the update task in the callback at a higher priority. We know that React sets a lot of different priorities for updates. If an update task is inside the flushSync callback, it gets a higher-priority update. Such as

import ReactDOM from 'react-dom' class Index extends React.Component{ state={ number:0 } handerClick=()=>{ setTimeout(()=>{ this.setState({ number: 1 }) }) this.setState({ number: 2 }) ReactDOM.flushSync(()=>{ this.setState({ number: 3 }) }) this.setState({ number: 4})} render(){const {number} = this.state console.log(number) Return <div> <div>{number}</div> <button onClick={this.handerclick} > flushSync</button> </div>}}Copy the code

unmountComponentAtNode

Uninstalling a component from the DOM removes its event handler and state. If there is no corresponding mounted component on the specified container, this function does nothing. Return true if the component has been removed, false if no component can be removed.

function Text(){ return <div>hello,world</div> } class Index extends React.Component{ node = null constructor(props){ Super (props) this.state={numer:1,}} componentDidMount(){/* Create a container */ reactdom.render (<Text/>, Enclosing the node)} handerClick = () = > {/ * click uninstall container * / const state = ReactDOM. UnmountComponentAtNode (. This node) console. The log (state)  } render(){ return <div style={{ marginTop:'50px' }} > <div ref={ ( node ) => this.node = node } ></div> <button onClick={ this.handerClick } >click me</button> </div> } }Copy the code