When many students use React to develop, the actual use of react API is very few, basically stay in the Component, react. Memo and other levels, the actual React source code, exposed methods are not many, but we rarely use. However, it is not useless to expose so many apis in React. If you want to play React, you need to understand what these apis are and what their application scenarios are. Today, let’s review the exposed apis in React production environment at one time (covering 90%+).

We divided the React API into component classes, tool classes, hooks, and react-DOM, and discussed them separately.

In order to make you in front of the screen better understand the API, I have racked my brains. Basically, every API in this article will produce a demo effect to make up for the stupid react document 😂😂😂, and my understanding of the basic concepts of API. Creation is not easy, I hope you can give me a compliment in front of the screen, so as to encourage me to continue to create front hard text.

As usual, we begin today’s reading with a question.

  • 1 reactThe exposedapiWhat are there and how should they be used?
  • 2 reactWhat means of self-testing performance are provided?
  • 3 refSince it cannot be used in a function component, how does a parent control a function’s child componentstateAnd methods?
  • 4 createElementandcloneElementWhat’s the difference? What’s the application scenario?
  • 5 reactThe built-inchildrenWhat’s the difference between a traversal method and an array method?
  • 6 reactHow to render a child element into a specified container outside the parent element?
  • .

I’m sure after reading this article, all of these questions will be solved, right?

Component classes

Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class: Component class Fragment,StrictMode, higher-order components such as forwardRef,memo, etc.

Component

Component is the foundation of class components. It all starts with Component. We have nothing to say about the use of react.ponent. Let’s focus here on what React does to the Component.

react/src/ReactBaseClasses.js

function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}
Copy the code

This is the Component function, where the updater object holds methods to update the Component.

When and how is our declared class component instantiated?

react-reconciler/src/ReactFiberClassComponent.js

constructClassInstance

function constructClassInstance(workInProgress, ctor, props){
   const instance = new ctor(props, context);
    instance.updater = {
        isMounted,
        enqueueSetState(){
            /* setState triggers this logic */
        },
        enqueueReplaceState(){},
        enqueueForceUpdate(){
            /* forceUpdate triggers this logic */}}}Copy the code

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.

PureComponent

PureComponent uses props and state to determine whether to rerender the Component. PureComponent uses props and state to determine whether to rerender the Component. Therefore, it is generally used for performance tuning to reduce render times.

What is called shallow comparison, let me give you an example:

class Index extends React.PureComponent{
    constructor(props){
        super(props)
        this.state={
           data: {name:'alien'.age:28
           }
        }
    }
    handerClick= () = >{
        const { data } = this.state
        data.age++
        this.setState({ data })
    }
    render(){
        const { data } = this.state
        return <div className="box" >
        <div className="show" >
            <div>Your name is: {data.name}</div>
            <div>Age: {data.age}</div>
            <button onClick={ this.handerClick } >age++</button>
        </div>
    </div>}}Copy the code

Click the button, nothing happensBecause thePureComponentThey compare it twicedataObject, all pointing to the same thingdataNo changes have been made, so the view is not updated.

The solution to this problem is as simple as writing in the handerClick event:

 this.setState({ data: {... data} })Copy the code

A shallow copy would solve the problem.

memo

Memo is a higher-order component that can be used by function components and class components. Instead, PureComponent is a react. memo that can only determine whether to render props or not. PureComponent is for props and state.

Memo takes two arguments. The first argument is the original component itself. The second argument determines whether the original component should be rerendered based on whether the props were the same during an update. Is a Boolean value that returns true to prove that the component does not need to be rerendered, and false to prove that the component needs to be rerendered. This is the opposite of shouldComponentUpdate() in class components.

React. Memo: The second argument returns true that the component is not rendered, and false that the component is rerendered. ShouldComponentUpdate: Returns true for component rendering, false for component not rendering.

Next, let’s make a scene that controls the component to render at a certain range with only one props number variable.

Example 🌰 :

Control the number in props:

  • 1 only number changes, component rendering.

  • 2 Only number less than 5, component rendering.

function TextMemo(props){
    console.log('Subcomponent Rendering')
    if(props)
    return <div>hello,world</div> 
}

const controlIsRender = (pre,next) = >{
   if(pre.number === next.number  ){ // The number is not changed and the component is not rendered
       return true 
   }else if(pre.number ! == next.number && next.number >5 ) { // The number is changed, but the value is greater than 5, and the component is not rendered
       return true
   }else { // Otherwise render the component
       return false}}const NewTexMemo = memo(TextMemo,controlIsRender)
class Index extends React.Component{
    constructor(props){
        super(props)
        this.state={
            number:1.num:1}}render(){
        const { num , number }  = this.state
        return <div>
            <div>Change num: current value {num}<button onClick={() = >this.setState({ num:num + 1 }) } >num++</button>
                <button onClick={() = >this.setState({ num:num - 1 }) } >num--</button>  
            </div>
            <div>Change number: current value {number}<button onClick={() = >this.setState({ number:number + 1 }) } > number ++</button>
                <button onClick={() = >this.setState({ number:number - 1 }) } > number -- </button>  
            </div>
            <NewTexMemo num={ num } number={number}  />
        </div>}}Copy the code

Effect:

To some extent, React. Memo is equivalent to shouldComponentUpdate, which is used to intercept new and old props and determine if the component is updated.

forwardRef

The concept and usage of forwardRef on the official website is very general, and no specific case is given. Many students do not know how to use the forwardRef. I will explain the application scenario of the forwardRef with specific examples.

1 Forward import Ref

The scenario is actually quite simple, say the parent component wants to get the grandson component, a DOM element. The forwardRef is needed to facilitate this.

function Son (props){
    const { grandRef } = props
    return <div>
        <div> i am alien </div>
        <span ref={grandRef} >This one is trying to get the element</span>
    </div>
}

class Father extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return <div>
            <Son grandRef={this.props.grandRef}  />
        </div>}}const NewFather = React.forwardRef((props,ref) = ><Father grandRef={ref}  {. props} / >  )

class GrandFather extends React.Component{
    constructor(props){
        super(props)
    }
    node = null 
    componentDidMount(){
        console.log(this.node)
    }
    render(){
        return <div>
            <NewFather ref={(node)= > this.node = node } />
        </div>}}Copy the code

The effect

React does not allow this function to be passed through the props, because the component already has this attribute called ref (props). This must be handled by the forwardRef during the component mediation process. It can be passed by props.

2 The high-order component forwards the Ref

As mentioned in this article, the attribute broker is covered with a layer of hoc, so if it is a class component, it can’t get the original component instance through the ref, but we can forward the ref through the forWardRef.

function HOC(Component){
  class Wrap extends React.Component{
     render(){
        const{ forwardedRef ,... otherprops } =this.props
        return <Component ref={forwardedRef}  {. otherprops} / >}}return  React.forwardRef((props,ref) = > <Wrap forwardedRef={ref} {. props} / >)}class Index extends React.Component{
  componentDidMount(){
      console.log(Awesome!)}render(){
    return <div>hello,world</div>}}const HocIndex =  HOC(Index,true)
export default() = > {const node = useRef(null)
  useEffect(() = >{
     /* Capture an instance of the Index component across the hierarchy */ 
    console.log(node.current.componentDidMount)
  },[])
  return <div><HocIndex ref={node}  /></div>
}

Copy the code

As mentioned above, the problem of introducing high order components into refs is resolved.

lazy

The React. Lazy and Suspense techniques do not yet support server rendering. We recommend Loadable Components if you want to use it in an application that uses server-side rendering

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.

We simulate a dynamic loading scenario.

The parent component

import Test from './comTest'
const LazyComponent =  React.lazy(() = > new Promise((resolve) = >{
      setTimeout(() = >{
          resolve({
              default: () = > <Test />})},2000)}))class index extends React.Component{   
    render(){
        return <div className="context_box"  style={ { marginTop :'50px'}} >
           <React.Suspense fallback={ <div className="icon" ><SyncOutlined  spin  /></div> } >
               <LazyComponent />
           </React.Suspense>
        </div>}}Copy the code

We use setTimeout to simulate the import asynchronous import effect.

Test

class Test extends React.Component{
    constructor(props){
        super(props)
    }
    componentDidMount(){
        console.log('--componentDidMount--')}render(){
        return <div>
            <img src={alien}  className="alien" />
        </div>}}Copy the code

The effect

Suspense

What is Suspense? Suspense makes a component “wait” for an asynchronous action until it finishes rendering.

Suspense for data capture is a new feature that you can use to “wait” for anything, including data, in a declarative way. This article focuses on its use case for data capture, but it can also be used for waiting for images, scripts, or other asynchronous operations.

When I mentioned the higher-order component Lazy, the asynchronous rendering component has been built using the Lazy + Suspense pattern. Let’s take a look at the example in the official website documentation:

const ProfilePage = React.lazy(() = > import('./ProfilePage')); / / lazy loading
<Suspense fallback={<Spinner />} ><ProfilePage />
</Suspense>
Copy the code

Fragment

React does not allow a component to return more than one node element, such as the following

render(){
    return <li>🍎 🍎 🍎</li>
           <li>🍌 🍌 🍌</li>
           <li>🍇 🍇 🍇</li>
}
Copy the code

If we want to solve this situation, we simply need to wrap a container element around it.

render(){
    return <div>
           <li>🍎 🍎 🍎</li>
           <li>🍌 🍌 🍌</li>
           <li>🍇 🍇 🍇</li>
    </div>
}
Copy the code

But we don’t expect additional DOM nodes to be added, so React provides the concept of fragments that allow a component to return multiple elements. So we could write it this way

<React.Fragment>
    <li>🍎 🍎 🍎</li>
    <li>🍌 🍌 🍌</li>
    <li>🍇 🍇 🍇</li>
</React.Fragment>
Copy the code

It can also be abbreviated as:

<>
    <li>🍎 🍎 🍎</li>
    <li>🍌 🍌 🍌</li>
    <li>🍇 🍇 🍇</li>
</>
Copy the code

The difference between Fragment and Fragment is that Fragment can support the key attribute. <> The key attribute is not supported.

Warm tips. The react layer handles the elements we traverse through the map, and by default we nest a

outside.

Such as:

{[1.2.3].map(item= ><span key={item.id} >{ item.name }</span>)}Copy the code

React is equivalent to:

<Fragment>
   <span></span>
   <span></span>
   <span></span>
</Fragment>
Copy the code

Profiler

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.

Practice:

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

onRender

  • 0 -id: root -> ProfilerOf the treeid
  • 1 -phase: mount -> mountMount,updateApply colours to a drawing.
  • 2 -actualDuration: 6.685000262223184– > updatecommittedRendering time spent.
  • 3 -baseDuration: 4.430000321008265-> time required to render the entire subtree
  • 4 -startTime : 689.7299999836832-> Start rendering time for this update
  • 5 -commitTime : 698.5799999674782-> When committed will be updated
  • 6 -interactions: set{}-> This updateinteractionsA collection of

Although profilers are lightweight components, they should be used only when needed. For an application, each addition imposes some burden on the CPU and memory.

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.

StrictMode currently helps:

  • ① Identify the life cycle of insecurity.
  • ② About using outdated stringsref APIThe warning
  • ③ About the use of wastefindDOMNodeMethod warning
  • (4) Detect unintended side effects
  • ⑤ Detection out of datecontext API

Practice: Identify insecure lifecycles

Not safe for the life cycle of means UNSAFE_componentWillMount, UNSAFE_componentWillReceiveProps, UNSAFE_componentWillUpdate

Outer layer in strict mode:

<React.StrictMode> 
    <Router  >
        <Meuns/>
        <KeepaliveRouterSwitch withoutRoute >
            { renderRoutes(menusList) }
        </KeepaliveRouterSwitch>
    </Router>
</React.StrictMode>
Copy the code

We use insecure lifecycles in inner components:

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

Effect:

Utility class

Let’s explore the use of the React utility class functions.

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. I’m going to write a component, and let’s see what it compiles to,

If we write this in Render:

render(){
    return <div className="box" >
        <div className="item"  >The life cycle</div>
        <Text  mes="hello,world"  />
        <React.Fragment> Flagment </React.Fragment>{/* */} text Indicates the text</div>
}
Copy the code

It will compile like this:

render() {
    return React.createElement("div", { className: "box" },
            React.createElement("div", { className: "item" }, "\u751F\u547D\u5468\u671F"),
            React.createElement(Text, { mes: "hello,world" }),
            React.createElement(React.Fragment, null." Flagment "),
            "text\u6587\u672C");
    }
Copy the code

Of course, we can develop directly through createElement without JSX mode.

createElementModel:

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

CreateElement method parameters:

** 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.

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

Other parameters:, are children in order.

What does createElement do?

After createElement processing, $$Typeof = Symbol(React. Element) object is finally formed. Object holds information about the React. Element.

cloneElement

Some students may also be silly not clear cloneElement and createElement difference and function.

CreateElement turns the JSX object that we wrote into an Element object; CloneElement is used to clone and return a new React element from the element template. The props of the returned element are the result of a shallow combination of the new props and the original props.

So cloneElement might not be useful in our actual business components, but it’s useful in some open source projects or public slot components. For example, we can hijack the Children Element in the component and clone the Element through cloneElement. With the 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

Print:

Perfect!

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)
Copy the code

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.

Let’s simulate context. Provider and context. Consumer:

function ComponentB(){
    /* Subscription with Consumer, from the Provider value change */
    return <MyContext.Consumer>
        { (value) => <ComponentA  {. value} / > }
    </MyContext.Consumer>
}

function ComponentA(props){
    const { name , mes } = props
    return <div> 
            <div>Name: {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:

Providers and consumers have good features. They can store and fetch data. Consumers can pass value on the one hand and subscribe to changes in value on the other.

The Provider also has a feature that allows you to pass values through layers. This feature is fully demonstrated in React-Redux.

createFactory

React.createFactory(type)
Copy the code

Returns the function used to generate the React element of the specified type. Type parameters can be either tag name strings (like ‘div’ or ‘span’), React component types (class or function components), or React Fragments.

Use:

 const Text = React.createFactory(() = ><div>hello,world</div>) 
function Index(){  
    return <div style={{ marginTop:'50px'}} >
        <Text/>
    </div>
}
Copy the code

The effect

It warns that the API will be deprecated, which we won’t go into here, but if you want the same effect, use React. CreateElement

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

Personally, I think createRef is a very weak method, but we could have written this in the class component to capture the ref.

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

Or write this in the 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.

practice

Let’s do a scenario that validates all children of a container component and filters them to non-React Element types.

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

The effect before filtering

We useisValidElementforreact elementValidation:

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

Effect after filtration

Let’s learn react Together filters out non-react elements! .

Children.map

The following five apis are related to React. Chidren. Let’s take a look at the descriptions on the official website.

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

print

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

print

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.

But let’s use the WarpComponent for children with React.Chidren:

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

At this point, you can iterate normally and achieve the desired effect.

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.

Let’s change the WarpComponent method above to children.foreach.

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

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.

Let’s change the above example:

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

Effect:

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

Effect:

NewChidrenArray is just a flat array structure. React.children.toarray () changes the key value to preserve the semantics of nested arrays when it flattens out the list of child nodes. That is, toArray prefixes each key in the returned array so that the range of each element key is limited to the objects that this function adds to its argument group.

Children.only

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

Is not the only

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

The effect

The only

function WarpComponent(props){
    console.log(React.Children.only(props.children))
    return props.children
}   
function Index(){
    return <div style={{ marginTop:'50px'}} >
        <WarpComponent>
           <Text/>
        </WarpComponent>
    </div>
}
Copy the code

The effect

React.children.only () does not accept the react.children.map () return value because it is an array and not a React element.

react-hooks

For react-hooks, I have written a trilogy, which introduces the use of React-hooks, custom hooks, and the principles of React-hooks. If you are interested in it, you can check it out. There is a link at the end of the article. And made the corresponding simplification and some content of the supplement.

useState

UseState makes up for the fact that function components do not have state. UseState can accept either an initial value or a function action, which returns the value as the new state. Returns an array with the first value being the state read value and the second value being the dispatchAction function that changes the state.

Let’s look at an example:

const DemoState = (props) = > {
   /* setNumber is the function that sends updates */
   let [number, setNumber] = useState(0) /* 0 is the initial value */
   return (<div>
       <span>{ number }</span>
       <button onClick={() = >{setNumber(number+1) {setNumber(number=>number +1)} } >num++</button>
   </div>)}Copy the code

useEffect

UseEffect makes up for the fact that function components have no life cycle. We can use the useEffect callback function as the first argument to do the request data, event listening, etc., and the second argument as the deP dependency. When the dependency changes, we can re-execute the first function.

UseEffect can be used for data interaction.

/* Simulate data interaction */
function getUserInfo(a){
    return new Promise((resolve) = >{
        setTimeout(() = >{ 
           resolve({
               name:a,
               age:16,}}),500)})}const DemoEffect = ({ a }) = > {
    const [ userMessage , setUserMessage ] :any= useState({})
    const div= useRef()
    const [number, setNumber] = useState(0)
    /* Simulate event listener handler */
    const handleResize =() = >{}
    /* useEffect (); /* useEffect ()
    useEffect(() = >{
        /* Request data */
       getUserInfo(a).then(res= >{
           setUserMessage(res)
       })
       /* Operate dom */
       console.log(div.current) /* div */
       /* Event listener */
        window.addEventListener('resize', handleResize)
    / * only when the props - > a and the state - > number change, useEffect side effect function to perform, if the array is empty [], that function only at the time of initialization performs a equivalent componentDidMount * /
    },[ a ,number ])
    return (<div ref={div} >
        <span>{ userMessage.name }</span>
        <span>{ userMessage.age }</span>
        <div onClick={() = > setNumber(1) } >{ number }</div>
    </div>)}Copy the code

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 }) = > {
    /* Simulate event listener handler */
    const handleResize =() = >{}
    useEffect(() = >{
       /* Timer delay, etc. */
       const timer = setInterval(() = >console.log(Awesome!),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

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.

Application scenarios: 1 Cache some values to avoid re-executing the context

const number = useMemo(() = >{
    / * *... Lots of logical operations **/
   return number
},[ props.number ]) // If only props. Number changes, recalculate the number.
Copy the code

Reduce the unnecessarydomcycle

/* A list wrapped in useMemo can be restricted to updating the list if and only if the list changes, thus avoiding selectList recycling */
 {useMemo(() = > (
      <div>{
          selectList.map((i, v) => (
              <span
                  className={style.listSpan}
                  key={v} >
                  {i.patentName} 
              </span>
          ))}
      </div>
), [selectList])}

Copy the code

Reduce subcomponent rendering

/* The child component will render */ only if the list of props changes
const  goodListChild = useMemo(() = > <GoodList list={ props.list} / > ,[ props.list ])
Copy the code

useCallback

Both useMemo and useCallback receive the same parameters. Both are executed after their dependencies have changed, and both return cached values. The difference is that useMemo returns the result of a function run, while useCallback returns the function. The returned callback can be passed to the child component as the props callback function.

/ * the react. Memo * /
const DemoChildren = React.memo((props) = >{
   /* Only when the child component is initialized is printed */
    console.log('Child Component Update')
   useEffect(() = >{
       props.getInfo('Child component')
   },[])
   return <div>Child components</div>
})
const DemoUseCallback=({ id }) = >{
    const [number, setNumber] = useState(1)
    /* The first parameter of usecallback (sonName)=>{console.log(sonName)} is assigned to getInfo */
    const getInfo  = useCallback((sonName) = >{
          console.log(sonName)
    },[id])
    return <div>{/* Click the button to trigger the parent component update, but the child component is not updated */}<button onClick={() = >SetNumber (number+1)} > increment</button>
        <DemoChildren getInfo={getInfo} />
    </div>
}
Copy the code

useRef

What useRef does:

  • One is that it can be used to obtaindomElement, orclassComponent instance.
  • twoThe react - hooks principleIn the article, we talked about creatinguseRefWhen the function is created, an original object is created. The original object will exist as long as the function component is not destroyeduseRefSave some data.
const DemoUseRef = () = >{
    const dom= useRef(null)
    const handerSubmit = () = >{
        /* 
      
Form component
DOM node */
console.log(dom.current) } return <div>{/* ref mark the current DOM node */}<div ref={dom} >Form components</div> <button onClick={()= >Submitted handerSubmit ()} ></button> </div> } Copy the code

useLayoutEffect

UseEffect execution order: Component update is mounted -> browser DOM drawing is completed -> Execute useEffect callback. UseLayoutEffect execution sequence: Component update is mounted -> perform useLayoutEffect callback -> Browser DOM drawing is completed.

So the useLayoutEffect code may block the browser’s drawing. We write effect and useLayoutEffect and React on the bottom layer and PassiveEffect and HookLayout on the bottom layer, and then in the commit phase, when to do it.

const DemoUseLayoutEffect = () = > {
    const target = useRef()
    useLayoutEffect(() = > {
        /* We need to move the DOM to the specified position before the DOM is drawn */
        const { x ,y } = getPositon() /* Get the x,y coordinates */ to move
        animate(target.current,{ x,y })
    }, []);
    return (
        <div >
            <span ref={ target } className="animate"></span>
        </div>)}Copy the code

useReducer

As explained in the React-hooks principles article, the useState base is a simple 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.

Let’s take a look at how useReducer works:

const DemoUseReducer = () = >{
    /* Number is the updated state value. DispatchNumbner is the current dispatcher function */
   const [ number , dispatchNumbner ] = useReducer((state,action) = >{
       const { payload , name  } = action
       /* The return value is the new state */
       switch(name){
           case 'add':
               return state + 1
           case 'sub':
               return state - 1 
           case 'reset':
             return payload       
       }
       return state
   },0)
   return <div>Current value: {number} {/* Dispatch update */}<button onClick={()= >DispatchNumbner ({name:'add'})} > Is added</button>
      <button onClick={()= >DispatchNumbner ({name:'sub'})} > Reduced</button>
      <button onClick={()= >DispatchNumbner ({name:'reset',payload:666})} > Assignment</button>{/* pass the dispatch and state to the child components */}<MyChildren  dispatch={ dispatchNumbner } State={{ number}} / >
   </div>
}
Copy the code

useContext

We can use useContext to get the value of the context passed by the parent component. The current value is the value set by the most recent parent component Provider. The useContext parameter is usually introduced by the createContext mode and can also be passed by the parent context context (the parameter is context). UseContext can be used instead of context.Consumer to get the value stored by the Provider

/* Use useContext */
const DemoContext = () = > {
    const value:any = useContext(Context)
    /* my name is alien */
return <div> my name is { value.name }</div>
}
/* Use context. Consumer */
const DemoContext1 = () = >{
    return <Context.Consumer>
         {/*  my name is alien  */}
        { (value)=> <div> my name is { value.name }</div> }
    </Context.Consumer>
}

export default() = > {return <div>
        <Context.Provider value={{ name:'alien',age:18 }} >
            <DemoContext />
            <DemoContext1 />
        </Context.Provider>
    </div>
}
Copy the code

useImperativeHandle

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.

Let’s simulate the scene withuseImperativeHandleTo enable the parent component to enable the child component ininputAutomatically assign and focus.

function Son (props,ref) {
    console.log(props)
    const inputRef = useRef(null)
    const [ inputValue , setInputValue ] = useState(' ')
    useImperativeHandle(ref,() = >{
       const handleRefs = {
           /* Declare a method to focus the input box */
           onFocus(){
              inputRef.current.focus()
           },
           /* Declare methods to change the value of input */
           onChangeValue(value){
               setInputValue(value)
           }
       }
       return handleRefs
    },[])
    return <div>
        <input
            placeholder="Please enter content"
            ref={inputRef}
            value={inputValue}
        />
    </div>
}

const ForwarSon = forwardRef(Son)

class Index extends React.Component{
    inputRef = null
    handerClick(){
       const { onFocus , onChangeValue } =this.cur
       onFocus()
       onChangeValue('let us learn React! ')}render(){
        return <div style={{ marginTop:'50px'}} >
            <ForwarSon ref={node= > (this.inputRef = node)} />
            <button onClick={this.handerClick.bind(this)} >Control subunit</button>
        </div>}}Copy the code

Effect:

useDebugValue

UseDebugValue can be used to display a label for custom hooks in the React developer tools. The purpose of this hooks is to check custom hooks

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);
  // ...
  // Display the tag next to the Hook in the developer tools
  // e.g. "FriendStatus: Online"
  useDebugValue(isOnline ? 'Online' : 'Offline');

  return isOnline;
}
Copy the code

We do not recommend that you add debug values to every custom Hook. It is most valuable when it is part of a shared library. In some cases, the display of formatted values can be an expensive operation. This is not necessary unless you need to check the Hook. Therefore, useDebugValue accepts a formatting function as an optional second argument. This function is called only if the Hook is checked. It accepts the debug value as an argument and returns a formatted display value.

useTransition

UseTransition allows a delay in rendering a view caused by a state change. Avoid unnecessary renderings. It also allows components to defer slower data fetch updates until later rendering so that more important updates can be rendered immediately.

const TIMEOUT_MS = { timeoutMs: 2000 }
const [startTransition, isPending] = useTransition(TIMEOUT_MS)
Copy the code
  • UseTransition accepts an object, timeoutMs the amount of time the code needs to delay.

  • Returns an array. The first argument: is a function that accepts a callback. We use it to tell React what state we need to postpone. The second parameter: a Boolean value. Indicates whether you are waiting for the completion of the transition state (delaying the update of the state).

Let’s introduce the example of the official website, to understand the use of useTransition.

const SUSPENSE_CONFIG = { timeoutMs: 2000 };

function App() {
  const [resource, setResource] = useState(initialResource);
  const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);
  return (
    <>
      <button
        disabled={isPending}
        onClick={()= > {
          startTransition(() => {
            const nextUserId = getNextId(resource.userId);
            setResource(fetchProfileData(nextUserId));
          });
        }}
      >
        Next
      </button>{isPending ? "Loading..." : null}<Suspense fallback={<Spinner />} ><ProfilePage resource={resource} />
      </Suspense>
    </>
  );
}
Copy the code

In this code, we wrap our data fetch with startTransition. This allows us to start fetching the user profile data immediately, while delaying the rendering of the next user profile page and its associated Spinner for 2 seconds (the time displayed in timeoutMs).

This API is currently in the experimental stage and has not been fully opened up.

react-dom

Next, let’s take a look at the react-DOM apis.

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])
Copy the code

use

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

Reactdom. render controls the contents of the container node, but does not modify the container node itself.

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])
Copy the code

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, the global popover component model, the < model /> component is usually 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)
Copy the code

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

Let’s put this into practice:

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

The effect

We can see that our children are actually mounted outside of the container, but have been rendered into the Container by createPortal.

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 effect

Render times once.

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

The effect

Render three times.

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

ReactDOM.flushSync(() = >{
    /* This update will set a higher priority update */
    this.setState({ name: 'alien'})})Copy the code

So in order for you to understand flushSync, I’m going to do a demo here,

/* flushSync */
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) // Print what??
        return <div>
            <div>{ number }</div>
            <button onClick={this.handerClick} >Test flushSync</button>
        </div>}}Copy the code

Let’s not look at the answer, let’s click the button and print what?

Let’s click and see

Print 0, 3, 4, 1. I’m sure it’s easy to see why.

  • First of all,flushSync this.setState({ number: 3 })A high priority update is set, so 3 is printed first
  • 2 4 is updated to 4 in batches

I believe this demo gave us a deeper understanding of flushSync.

findDOMNode

FindDOMNode is used to access component DOM element nodes. React recommends the REF mode and does not expect findDOMNode.

ReactDOM.findDOMNode(component)
Copy the code

Note that:

  • 1 findDOMNode can only be used on mounted components.

  • FindDOMNode returns null if the component render content is NULL or false.

  • 3 findDOMNode cannot be used for function components.

Let’s take a look at how findDOMNode works:

class Index extends React.Component{
    handerFindDom=() = >{
        console.log(ReactDOM.findDOMNode(this))}render(){
        return <div style={{ marginTop:'100px'}} >
            <div>hello,world</div>
            <button onClick={ this.handerFindDom } >Getting the container DOM</button>
        </div>}}Copy the code

Effect:

We could have marked the outer container with ref to capture the native DOM node.

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.

Let’s take a simple example to see how unmountComponentAtNode is used.

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 */ when the component is initialized
        ReactDOM.render(<Text/> , this.node )
    }
    handerClick=() = >{
       /* Click Uninstall container */ 
       const state =  ReactDOM.unmountComponentAtNode(this.node)
       console.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

The effect

conclusion

In this paper, I have learned the usage of API from react component level, tool level, hooks level and React-DOM. I hope that students who have finished reading this article can type the demo by themselves, and in the end, they will find that they have grown a lot.

Finally, send roses, hand left fragrance, feel that there is a harvest of friends can give the author thumbs up, concern a wave, one after another update front-end super-core articles.

Leak ahead: There will be an article revealing the React incident system.

Interested students please follow the public accountThe front-end SharingKeep pushing good quality articles

Last react article

In this article, I recommend that you read the react-hooks trilogy.

The react – hooks trilogy

  • How do you use 150+ likes 👍

  • The second part: React-hooks, custom hooks design mode and its actual combat 240+ 👍 praise

  • “React advanced” : understand the react-hooks principle 820

React Advanced series

  • React Advancements: eight year-end improvements sent to React developers 918+ likes 👍

  • “React Advanced” article understand react Advanced component (HOC) 330+ praise 👍

React source series

  • “Source code parse” this time thoroughly understand the react-router routing principle 132+ + 👍

  • “Source code parsing” an article understand react-Redux source code (useMemo classic source code level cases) 143+ praise 👍

Open Source Project Series

  • React Cache page from requirement to open source (how did I impress my product sister) 300+ likes 👍

  • “Front-end engineering” builds react, TS scaffolding from 0-1 (1.2w word ultra detailed tutorial) 330+ praise 👍

Reference documentation

React Chinese Documents