React Hooks are a new feature in React version 16.8 that advocates using function components. In older versions of React, function components have no instance, no state, and no lifecycle functions, resulting in the use of class components in many cases. But with Hooks we can use state and other React features without using class components!

A useState.

1. Use useState

import React, { useState } from 'react';

function Example() {// declare a call"count"State variable const [count,setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Copy the code
  • This is an official basic usage example, where import introduces the useState function
  • The initialized value is passed in when the function is called
  • The function returns an array: one for the initialized state and one for the updated state
  • Finally, use state elsewhere, or call a function that updates state
  • Note: The function that updates state replaces state directly, rather than merging old and new states like setState did before

2. Use push, pop, splice, etc to directly change the pits of array objects

Because the update function of useState will directly replace the old state, we cannot add and delete the state of objects or arrays by using push, pop, splice and other methods to directly change the array

Examples of errors:

import React, { useState } from "react";

function Comment() {
  const [counts, setCounts] = useState([1, 2]); Const handleAdd = () => {const randomCount = math.round (math.random ()*100setCounts(counts.push(randomCount))
  }
  return(< div > {counts. The map ((count) = > (< div key = {count} > {count} < / div >))} < button onClick = {handleAdd} > add < / button > < / div >). }export default Comment;

Copy the code

The correct method should be to use array deconstruction to generate a new array, add our new random number to the end of the array to achieve the new array items, and use the filter array filtering method to achieve the operation of deleting the items.

Array new item:

import React, { useState } from "react";

function Comment() {
  const [counts, setCounts] = useState([1, 2]); Const handleAdd = () => {const randomCount = math.round (math.random ()*100setCounts([
      ...counts,
      randomCount
    ])
  }
  return(< div > {counts. The map ((count) = > (< div key = {count} > {count} < / div >))} < button onClick = {handleAdd} > add < / button > < / div >). }export default Comment;

Copy the code

Delete the entry

import React, { useState } from "react";

function Comment() {
  const [counts, setCounts] = useState([1, 2, 3, 4]); Const handleDel = () => {// Remove unwanted items using the array filter methodsetCounts(counts.filter((count, index) => index ! == counts.length - 1)) }return(< div > {counts. The map ((count) = > (< div key = {count} > {count} < / div >))} < button onClick = {handleDel} > delete < / button > < / div >). }export default Comment;

Copy the code

In addition, there is another method similar to the previous reducer that used redux to make a deep copy of the old array objects, and then add and delete them, and finally return them

import React, { useState } from "react";

function Comment() {
  const [counts, setCounts] = useState([1, 2]);
  const handleAdd = () => {
    setCounts(counts => { const randomCount = Math.round(Math.random()*100) // Simply use json. parse and json. stringify to deeply copy a new array and object (in real projects it is recommended to write your own recursive deep-copy function) and return the operationlet newCounts = JSON.parse(JSON.stringify(counts))
      newCounts.push(randomCount)
      return newCounts
    })
  }
  return(< div > {counts. The map ((count) = > (< div key = {count} > {count} < / div >))} < button onClick = {handleAdd} > add < / button > < / div >). }export default Comment;

Copy the code

3. Each render is a pit of a separate closure

The count in the asynchronous function is the value (0) in the closure of the previous execution. This is an error:

import React, { useState } from "react";

function Comment() {
  const [count, setCount] = useState(0);
  const handleAdd = () => setCount(count + 1);
  const handleSyncAdd = () => {
    setTimeout(() => {// Retrieves the state in the closuresetCount(count + 1);
    }, 1000);
  };
  return(<div> <p>{count}</p> <button onClick={handleAdd}> add </button> <button onClick={handleSyncAdd}> add </button> </div>); }export default Comment;

Copy the code

In this case we use a callback function update

Correct examples:

import React, { useState } from "react";

function Comment() {
  const [count, setCount] = useState(0);
  const handleAdd = () => setCount(count + 1);
  const handleSyncAdd = () => {
    setTimeout(() => {// Update the callback function to receive the previous state each time the callback function executes, instead of the state in the closuresetCount(count => count + 1);
    }, 1000);
  };
  return(<div> <p>{count}</p> <button onClick={handleAdd}> add </button> <button onClick={handleSyncAdd}> add </button> </div>); }export default Comment;
Copy the code

Second, the useEffect

  • An effect can be understood as a lifecycle function when we use a class component
  • UseEffect can implement what we have in class componentscomponentDidMount,ComponentDidUpdateandcomponentWillUnmountIt’s just merged into an API
  • withcomponentDidMountcomponentDidUpdateThe difference is the useuseEffectDoesn’t block the browser update screen, making your app seem more responsive. In most cases, effects do not need to be executed synchronously. In individual cases (such as measuring layout), there are separateuseLayoutEffectFor you to use, its API withuseEffectThe same.

UseEffect implements componentDidMount and ComponentDidUpdate

UseEffect directly to pass in a callback function that is executed on the first rendering of the component and each update rendering

import React, { useState, useEffect } from 'react'

function Parent() {
  const [count, setCount] = useState(0)
  const handleAdd = () => setUseEffect (() => {console.log() => {console.log() => {console.log();'parent effect');
  })
  return<div> parent, {count} <button onClick={handleAdd}> add </button> </div>export default Parent

Copy the code

2. Implement componentDidMount with useEffect

Most of the time we just need to do something with the first load of the component, such as ajax fetching data, etc. We just need to pass in an empty array as the second parameter of useEfffect. This array means that effect is executed when the value in the array is updated

import React, { useState, useEffect } from 'react'

function Parent() {
  const [count, setCount] = useState(0)
  const handleAdd = () => setUseEffect (() => {console.log() => {console.log() => {console.log())'parent didMount');
  }, [])
  return<div> parent, {count} <button onClick={handleAdd}> add </button> </div>export default Parent

Copy the code

You can also pass a value in the second array to indicate that effect is executed on update

import React, { useState, useEffect } from 'react'

function Parent() {
  const [count, setCount] = useState(0)
  const handleAdd = () => setCount(Count + 1) // The second argument is passed to an array containing Count. Effect useEffect(() => {console.log())'count update');
  }, [count])
  return<div> parent, {count} <button onClick={handleAdd}> add </button> </div>export default Parent

Copy the code

3. UseEffect to implement componentWillUnmout function

UseEffect returns a function that completes the componentWillUnmout function when the component is uninstalled

import React, { useState, useEffect } from 'react'

function Parent() {
  const [count, setCount] = useState(0)
  const handleAdd = () => setUseEffect (() => {console.log() => {console.log())'component mount');
    return () => {
      console.log('component unmount'); }})return<div> parent, {count} <button onClick={handleAdd}> add </button> </div>export default Parent

Copy the code

Third, useMemo

UseMemo can be briefly understood as a calculated attribute in Vue. When a dependent attribute changes, the calculation is automatically performed and the final value is returned (and cached, and recalculated only when the dependency changes). For high performance consumption, useMemo must be used or the recalculation will occur every update.

Example:

import React, { useState, useMemo } from 'react'

function Parent() {
  const [count, setCount] = useState(0)
  const [price, setPrice] = useState(1)
  const handleCountAdd = () => setCount(count + 1)
  const handlePriceAdd = () => setConst all = useMemo(() => count * Price, [count, Price])return( <div> parent, <button onClick={handleCountAdd}> </button onClick={handleCountAdd}> </button> <p>count: {count}, price: {price} all: {all}</p> </div> ) }export default Parent

Copy the code

Four, useCallback

UseCallback differs from useMemo in that useMemo is a cached value. UseCallback is a cached function. When a parent component passes a parameter to a child component as a normal function, the parent component updates the child component every time. We use useCallback to define the function and pass it to the child component, which then updates it based on its dependencies

Example:

import React, { useState, useCallback, useEffect } from 'react';
function Parent() {
    const [count, setCount] = useState(1);
    const [val, setVal] = useState(' ');
 
    const callback = useCallback(() => {
        return count;
    }, [count]);
    return <div>
        <h4>{count}</h4>
        <Child callback={callback}/>
        <div>
            <button onClick={() => setCount(count + 1)}>+</button>
            <input value={val} onChange={event => setVal(event.target.value)}/>
        </div>
    </div>;
}
 
function Child({ callback }) {
    const [count, setCount] = useState(() => callback());
    useEffect(() => {
      console.log(123);
        setCount(callback());
    }, [callback]);
    return <div>
        {count}
    </div>
}

export default Parent
Copy the code

Fifth, useReducer

Reducer is similar to useReducer and Redux, and is an alternative to useState. It receives a Reducer of the form (state, action) => newState and returns the current state and its accompanying dispatch method. (If you’re familiar with Redux, you already know how it works.)

UseReducer can be more useful than useState in some situations, such as when the state logic is complex and contains multiple subvalues, or when the next state depends on the previous state. Also, using useReducer can optimize performance for components that trigger deep updates because you can pass dispatches to child components instead of callbacks.

import React, { useReducer } from 'react'

function Parent() {
  const reducer = (state, action) => {
    switch (action.type) {
      case 'add':
        return {count: state.count + 1}
      case 'reduce':
        return {count: state.count - 1}
      default:
        throw new Error()
    }
  }
  letinitialState = 0 const init = (initialState) => ({ count: InitialState}) // The third argument is an lazy initialization function that can be used to perform complex calculations to return the final initialState, Const [state, dispatch] = useReducer(Reducer, initialState, init)return (
    <div>
      <p>{state.count}</p>
      <button onClick={() => dispatch({type: 'add'})}>add</button>
      <button onClick={() => dispatch({type: 'reduce'})}>reduce</button>
    </div>
  )
}

export default Parent

Copy the code

Six, useContext

UseContext can implement functions similar to the react-Redux plugin. The upper component creates a context using createContext and passes the context using < myContext.provider >. The underlying component uses useContext to receive the context.

Example:

import React, { useState, createContext, useContext } from "react"; // Create a context using createContext const CounterContext = createContext();function Parent() {
  const [count, setCount] = useState(0);

  returnProvider < counterContext. Provider value={{count,setCount }}>
      {count}
      <Child />
    </CounterContext.Provider>
  );
}

function Child() {// The child uses useContext to receive context const {count,setCount } = useContext(CounterContext);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>add</button>
    </div>
  );
}

export default Parent;
Copy the code

Seven, useLayoutEffect

It is used in the same way as useEffect, but it calls Effect synchronously after all DOM changes. You can use it to read DOM layouts and trigger rerenders synchronously. The update schedule inside useLayoutEffect is refreshed synchronously before the browser performs the drawing. UseEffect is asynchronous and useLayoutEffect is synchronous. It is recommended that you start with useEffect and only try using useLayoutEffect if it goes wrong

Eight, useRef

React Hooks to get DOM nodes

Example:

import React, { useRef } from 'react'

function ParentConst pRef = useRef(null) {// create a ref with useRef and bind it to the ref attribute in the label const pRef = useRef(null)return (
    <div>
      <p ref={pRef}>content</p>
    </div>
  )
}

export default Parent
Copy the code

Customize Hooks

Custom Hooks can be used in multiple components that are state independent. Custom Hooks are automatically defined starting with use

Example:

import React, { useState } from "react"; // Customize useCount Hooksfunction useCount() {
  const [count, setCount] = useState(0);
  return { count, setCount };
}

function Parent() {// use parent, state independent const {count,setCount } = useCount()
  return (
    <div>
      <p>parent</p>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>add</button>
      <Child />
    </div>
  );
}

function Child() {// state independent const {count,setCount } = useCount()
  return (
    <div>
      <p>child</p>
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 2)}>add</button>
    </div>
  );
}

export default Parent;
Copy the code

Use React Hooks to override the use of our class components. Use React Hooks to implement new projects.