This article has participated in the activity of “New person creation Ceremony”, and started the road of digging gold creation together.

When React 16.8 was released, it was almost 3 years ago that class components were stateful and functional components were stateless. I remember an interview question asking what is the difference between functional components and class components. Now think of a little ridiculous, ha ha, bring back a little short memory

introduce

Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class. React Hook Functional components can also have state and are much simpler to use than class components

I have to say that Hook saved React. I even think that if there was no Hook, React would not be used at all. Haha.

Therefore, this article mainly explains useState, useEffect, useContext, useReducer, useMemo, useCallback, useRef, useImperativeHandle these 8 apis

Here is mainly to explain the use of this Api and the use of the knot, after all, I am an implementation of ~

Online example Domesy/Hook

useState

In the class component, we define the variable and set this. State in constructor, while in the Hook we use useState

Function: Used to declare state variables, similar to this.state and this.setState in class

Code examples:

import React, { useState } from 'react';
import { Button } from 'antd';

const Mock: React.FC<any> = () = > {
  const [count, setCount ] = useState<number> (0)

  return (
    <div style={{display: 'flex', justifyContent: 'space-between', paddingRight: 200}} >
      <Button type='primary' onClick={()= >SetCount (count + 1)}> add 1</Button>
      <div>{count}</div>
    </div>
   );
};

export default Mock;
Copy the code

useEffect

  • A Side Effect is when a function does something that has nothing to do with the return value of its operation, such as requesting data, modifying global variables, printing, fetching data, setting up subscriptions, and manually changing the DOM in the React component
  • Integrate the original lifecycle method and receive through the second parameter

ComponentDidMount componentDidUpdate componentWillUnmount to a method, eliminate frequent definition of cumbersome

Code demo

import React, { useState, useEffect } from 'react';
  import { Button } from 'antd';

  const Mock: React.FC<any> = () = > {
    const [count, setCount ] = useState<number> (0)

    return (
      <div>
        <Button type='primary' onClick={()= >SetCount (count + 1)}> add one</Button>
        <Test count={count} />
      </div>
    );
  };

  const Test: React.FC<{count: number} > =({count}) = > {

    const [count1, setCount1 ] = useState<number | false> (false)
    const [count2, setCount2 ] = useState<number | false> (false)

    useEffect(() = > {
      setCount1(count)
    },[])

    useEffect(() = > {
      setCount2(count)
    },[count])

    return <div style={{display: 'flex', justifyContent: 'space-between', marginRight: 200.marginTop: 50}} >
      <div>Only execute once: {count1}</div>
      <div>Execute multiple times: {count2}</div>
    </div>
  }

  export default Mock;
Copy the code

useContext

  • UseContext implements cross-hierarchy transfer and data sharing
  • The function is a technique to provide globally shared data in a tree of contained components
  • You need the help of createContext to get the value from useContext via the countContext. Provider wrapped component

Purpose: Context, the corresponding Context, is intended to set up globally shared data, so that all components can be shared across the hierarchy

Code sample

import React, { useState, createContext, useContext } from 'react';
  import { Button } from 'antd';

  const CountContext = createContext(-1)

  const Mock: React.FC<any> = () = > {
    const [count, setCount ] = useState<number> (0)

    return (
      <div>
        <Button type='primary' onClick={()= >SetCount (count + 1)}> add 1</Button>
        <CountContext.Provider value={count}>
          <Test1 />
        </CountContext.Provider>
      </div>
    );
  };

  const Test1: React.FC<any> = () = > {
    const count = useContext(CountContext)

    return <div style={{marginTop: 20}} >Child component gets count: {count}<Test2 />
    </div>
  }

  const Test2: React.FC<any> = () = > {
    const count = useContext(CountContext)

    return <div style={{marginTop: 20}} >Count: {count}</div>
  }

  export default Mock;
Copy the code

useReducer

  • Setting unified State
  • Take two arguments, state Action, and return a state count(property value) and Dispatch (method)

Function: Functions like Redux, enhancing the function body

Detailed code

import React, { useState, useReducer } from 'react';
  import { Button } from 'antd';

  const Mock: React.FC<any> = () = > {
    const [count, dispatch] = useReducer((state:any, action: any) = > {
      switch(action? .type){case 'add':
          returnstate + action? .payload;case 'sub':
          returnstate - action? .payload;default:
          returnstate; }},0);

    return (
      <div>
        <div style={{display: 'flex', justifyContent: 'flex-start'}} >
          <Button type='primary' onClick={()= >Dispatch ({type: 'add', payload: 1})}> add 1</Button>
          <Button type='primary' onClick={()= >Dispatch ({type: 'sub', payload: 1})} style={{marginLeft: 24}}> minus 1</Button>
        </div>
        <div style={{marginTop: 20}} >count: {count}</div>
      </div>
    );
  };

  export default Mock;
Copy the code

useMemo

  • The use of useMemo is basically the same as that of useEffect
  • When a component is updated, the child component is refreshed even though it does not change state, whereas useMemo only listens for a specific value, that is, it does not update when the value has not changed
  • Obtaining the current value through complex calculations within a useMemo function does not need to be recalculated each time the parent component is updated, but only when the dependency changes

Function:When a child component is called in a parent component, the parent component’s state changes, causing the parent component to update, and the child component to update even though it has not changed. UseMemo is a function component’s way of preventing this from being unnecessary, so useMemo is generally an optimization tool

Code sample

  import React, { useState, useMemo } from 'react';
  import { Button } from 'antd';

  const Mock: React.FC<any> = () = > {
    const [count, setCount ] = useState<number> (0)

    const add = useMemo(() = > {
      return count + 1
    }, [count])

    return (
      <div style={{display: 'flex', justifyContent: 'space-between', paddingRight: 50}} >
        <Button type='primary' onClick={()= >SetCount (count + 1)}> add 1</Button>
        <div>count: {count}</div>
        <div>The number of times: {add}</div>
      </div>
    );
  };

  export default Mock;
Copy the code

useCallback

UseCallback is typically used to handle functions in a component when they are passed to child elements for callback use

This is similar to the useMemo method, except that useMemo caches variables and useCallBack caches functions

Code examples:

import React, { useState, useCallback } from 'react';
  import { Button } from 'antd';

  const MockMemo: React.FC<any> = () = > {
    const [count,setCount] = useState(0)
    const [show,setShow] = useState(true)

    const  add = useCallback(() = >{
      setCount(count + 1)
    },[count])

    return (
      <div>
        <div style={{display: 'flex', justifyContent: 'flex-start'}} >
          <TestButton title="Normal click" onClick={()= > setCount(count + 1) }/>
          <TestButton title="UseCallback click" onClick={add}/>
        </div>
        <div style={{marginTop: 20}} >count: {count}</div>
        <Button onClick={()= >{setShow(! Show)}} > switch</Button>
      </div>)}const TestButton = memo((props:any) = >{
    console.log(props.title)
    return <Button type='primary' onClick={props.onClick} style={props.title= = ='useCallback click' ? {
    marginLeft: 20
    } : undefined} >{props.title}</Button>
  })

  export default MockMemo;
Copy the code

useRef

  • UseRef is similar to this for the class component
  • You can pass in an initialValue, and the object has only one current attribute
  • UseRef does not change over the render lifecycle, which is fundamentally different from createRef

UseRef retrieves all attributes of the current element and returns a mutable ref object that has only the current attribute and can be set to initialValue

Code sample

  import React, { useState, useRef } from 'react';

  const Mock: React.FC<any> = () = > {
    const scrollRef = useRef<any> (null);
    const [clientHeight, setClientHeight ] = useState<number> (0)
    const [scrollTop, setScrollTop ] = useState<number> (0)
    const [scrollHeight, setScrollHeight ] = useState<number> (0)

    const onScroll = () = > {
      if(scrollRef? .current){letclientHeight = scrollRef? .current.clientHeight;// View area height
        let scrollTop  = scrollRef.current.scrollTop;  // Scroll bar scroll height
        let scrollHeight = scrollRef.current.scrollHeight; // Scroll content height
        setClientHeight(clientHeight)
        setScrollTop(scrollTop)
        setScrollHeight(scrollHeight)
      }
    }

    return (
      <div >
        <div >
          <p>Viewable height: {clientHeight}</p>
          <p>ScrollTop: {scrollTop}</p>
          <p>ScrollHeight: {scrollHeight}</p>
        </div>
        <div style={{height: 200.overflowY: 'auto'}} ref={scrollRef} onScroll={onScroll} >
          <div style={{height: 2000}} ></div>
        </div>
      </div>
    );
  };

  export default Mock;
Copy the code

Detailed code

import React, { useState, useRef, createRef } from 'react';
  import { Button } from 'antd';

  const CreateMock: React.FC<any> = () = > {
    const [renderIndex, setRenderIndex] = React.useState(1);
    const refFromUseRef = React.useRef<number> ();const refFromCreateRef = createRef<any> ();if(! refFromUseRef.current) { refFromUseRef.current = renderIndex; }if(! refFromCreateRef.current) {// @ts-ignore
      refFromCreateRef.current = renderIndex;
    }

    return <>
      <p>Current render index: {renderIndex}</p>
      <p>refFrom UseRef: {refFromUseRef.current}</p>
      <p>refFrom CreateRef: {refFromCreateRef.current}</p>
      <Button type='primary' onClick={()= >SetRenderIndex (renderIndex + 1)} > Click</Button>
    </>
  };

  export default CreateMock;
Copy the code

useImperativeHandle

When a page is very complex, we will modularize the page, which will be divided into many modules. Sometimes, we need to control the methods of other components on the outermost component, hoping that the click event of the outermost component will be executed at the same time. In this case, useImperativeHandle is needed

What it does: Allows you to customize the instance values exposed to the parent component when using ref.

Code sample

import React, { useState, useImperativeHandle, useRef } from 'react'; import { Button } from 'antd'; const Children: React.FC<any> = ({cRef}) => { const [count, setCount] = useState<number>(0) const add = () => { setCount((c) => c + 1) } useImperativeHandle(cRef, () => ({ add })) return <div style={{marginBottom: 20}} > < p > clicks: {count} < / p > < Button type = 'primary' onClick = {() = > add ()} > 1 < / Button > < / div >} const Mock: React.FC<any> = () => { const ref = useRef<any>(null) return ( <div> <Children cRef={ref} /> <Button type='primary' OnClick = {() = > {ref. Current. The add ()}} > parent node plus 1 < / Button > < / div >). }; export default Mock;Copy the code

The above is just my simple understanding and use of each Api. If it is wrong, please note it in the comments area (● ̄(日 本 国 日 本).

Other articles

  • React Hook has a life cycle? You know what?
  • Do you prefer to define states this way?