useState

UseState receives an initial value and returns a deconstructed array. The first value is the current state and the second value is the setState update function. UseState’s update function replaces the state instead of merging it.

Usage scenario: Function components need state values, similar to the state values of react components

import React, { useState } from 'react'; Function Example() {// declare a new state variable called "count", 0 is the default const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } export default Example;Copy the code

Default: useState() after parentheses, can be passed a value or a function that will only be rendered once

const [ count, setCount ] = useState(() => {
  return props.count || 0
})

Copy the code

Update Render: When we update the value with useState, the component is re-rendered. If the updated value passed in is unchanged, the component will not be re-rendered.

useReducer

Usage scenario: Because useState’s update function is a replacement, it is not desirable to use useState when dealing with complex state in function components, such as objects and arrays. Therefore, we use useReducer to solve this problem

const [state, dispatch] = useReducer(reducer, initialArg, init);

Copy the code

It receives a Reducer of the form (state, action) => newState and returns the current state and its matching dispatch method, initialArg being the initial value.

import React, { useReducer } from 'react'; Const initialState = {count: 0, name: 'name ', age: 1} const initialState = {count: 0, name:' name ', age: 1} function reducer(state, action) { switch (action.type) { case 'increment': return {... state, count: state.count + 1}; case 'decrement': return {... state, count: state.count - 1}; default: throw new Error(); } } function Example() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </> ); } export default Example;Copy the code

Init is a function that takes initialArg to operate on initialArg and returns a custom initial value.

import React, { useReducer } from 'react';
function init(initialCount) {
  return {count: initialCount};
}
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    case 'reset':
      return init(action.payload);
    default:
      throw new Error();
  }
}
function Example({initialCount}) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  return (
    <>
      Count: {state.count}
      <button
        onClick={() => dispatch({type: 'reset', payload: initialCount})}>
        Reset
      </button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}
export default Example;

Copy the code

useEffect

Use scenario: useEffect A function component that has a react declaration cycle. UseEffect is called after each render session of the component. UseEffect takes two arguments, the first being the execution function and the second an array []

If you’re familiar with React class lifecycle functions, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount

import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); const [dataSources, setDataSources] = useState([]); UseEffect (() => {console.log(" equivalent to life cycle: componentDidMount+componentDidUpdate") }); UseEffect (() => {console.log(" life cycle: componentDidMount"); } []); UseEffect (() => {console.log(" life cycle: ComponentDidMount ") console.log(" = componentDidUpdate")}, [dataSources]); UseEffect (() => {console.log() => {console.log() => {console.log() => {console.log() => {console.log() => {console.log() => {console.log() => {console.log() => {console.log(); ComponentDidMount ") returns a function that is executed when the component is unmounted. Return () => {console.log(' equivalent to declaration cycle: componentWillUnmount'); }} []); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } export default Example;Copy the code

Official tip: Unlike componentDidMount or componentDidUpdate, useEffect is asynchronous and is used

UseEffect scheduled effect does not block the browser update screen, making your application seem more responsive. The official recommendation is to use useEffect whenever possible; effects do not need to be executed synchronously

Use useLayoutEffect instead of useEffect is only used in rare cases (such as when measuring the layout, or when the page state value flickers bug) to form synchronization, which is executed immediately after the DOM update is complete, but runs before the browser does any rendering, blocking the browser’s rendering

The memo is similar to the react. PureComponent. The memo is a purely functional component that performs a shallow comparison of internal objects to determine whether to re-render them. import React, { useState, useCallback } from 'react'; function Example() { const [count, setCount] = useState(0); const [list, setList] = useState([]); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>addCount</button> <button onClick={() => setList([...list, 1])}>changeList</button> <Child list={list} /> </div> ); } const Child = (props) => {console.log(" accessing component Child ") return (<div> List is {props.list.join(',')}</div>)} export default Example;Copy the code

If we want the Child component to render only when the props passed in as the list changes, then use react. memo to change the Child as follows

Const Child = react.memo ((props) => {console.log(" accessing component Child ") return (<div> here is Child: {props.list.join(',')}</div>)})Copy the code

useCallback

Use scenario: useCallback is used to cache methods like this.onChange = defined in the React component constructor

Bind (this), returns a cached function. If the Child component is passed a function as an argument, the function is of reference type, so each time the Child component is passed a new function instance, as follows

import React, { useState, useCallback } from 'react'; function Example() { const [count, setCount] = useState(0); const [list, setList] = useState([]); const handleChange = () => { console.log(`selected`); } return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>addCount</button> <button onClick={() => setList([...list, 1])}>changeList</button> <Child list={list} handleChange={handleChange} /> </div> ); } const Child = react.memo ((props) => {console.log(" accessing component Child ") return (<div> List is {props.list.join(',')}</div>)}) export default Example;Copy the code

In this case, either the count state or the list state is changed, the Child component is rerendered using useCallback.

// The second argument is an empty array. You can also specify that the handleChange method depends on a state value, which is changed only when the state value changes

const handleChange = useCallback(() => { console.log(`selected`); }, []) / / or [list]Copy the code

useMemo

Usage scenario: The useMemo function is used to cache the status value of the operation to be calculated, similar to the calculation attribute of Vue. The first argument is a calculation function and must return a result, which returns a cached value. The second argument is an array [], which useMemo execution depends on the state value of the count group

import React, { useState, useCallback, useMemo } from 'react'; function Example() { const [count, setCount] = useState(0); const [list, setList] = useState([]); const [a, setA] = useState(0) const [b, setB] = useState(0) const handleChange = useCallback(() => { console.log(`selected`); },[]) // memoizedValue = useMemo(() => a + b, [a, b]) const memoizedValue = useMemo(() => a + b, [a, b]); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>addCount</button> <button onClick={() => setList([...list, 1]} > for changeList < / button > < button onClick = {() = > {setA (a + 1)}} > me a < / button > < button onClick = {() = > { </button> <Child list={list} memoizedValue={memoizedValue} handleChange={memoizedValue} /> </div>); } const Child = react.memo ((props) => {console.log(" accessing component Child ") return (<div> List is {props.list.join(',')}, {props. MemoizedValue}</div>)}) export default Example;Copy the code

UseRef and React. ForwardRef

useRef

UseRef can accept a default value and return a mutable object with the current attribute;

Use scenarios: 1. Obtain the instance of a subcomponent (the subcomponent must be a react class inherited component).

2. Get a DOM element from the component.

The react class inherits the this. XXX property from the react class. The useRef returns a current property that will not be repeated for the entire component’s color life.

Reason: Since useState holds variables that trigger the component render, defining global variables with useRef does not trigger the component render

import React, { useState, useRef } from 'react'; function Example() { const [count, setCount] = useState(0); Span const spanEl = useRef(null); const getSpanRef = () => { console.log(2, spanEl.current) }; Const sunEl = useRef(null); // Get react component const sunEl = useRef(null); const getRefBySun = () => { console.log(1, sunEl.current) }; IsClick = false const isClick = useRef(false); const addCount = () => { if (! isClick.current) { setCount(count + 1) isClick.current = true } }; return ( <> <button onClick={addCount}>addCount</button> <Sun ref={sunEl} count={count} /> <span < span onClick={getSpanRef}> < span</ button> <button OnClick ={getRefBySun}> </button> </>); Render () {const {count} = this. Props return (<div>{count}</div>) } } export default Example;Copy the code

React.forwardRef:

Usage scenario: Less commonly used, used in the parent component to get the child component’s DOM element as its own ref, and then manipulate the child component’s DOM element

import React, { useRef } from 'react'; function Example() { //ref const inputEl = useRef(null); const onButtonClick = () => { console.log(inputEl) inputEl.current.focus(); }; Return (<> <TextInputWithFocusButton ref={inputEl} onButtonClick={onButtonClick} /> <span> I am span</span> </>); // Subcomponent const TextInputWithFocusButton = (props) => {return (<> <input ref={props. Ref} type="text" /> <button onClick={props.onButtonClick}>Focus the input</button> </> ); } export default Example;Copy the code

The above code error: Warning: TextInputWithFocusButton: ref is not a prop.

To inject a new ref with the react. forwardRef wrapper, modify the TextInputWithFocusButton component as follows:

const TextInputWithFocusButton = React.forwardRef((props, ref) => {
  return (
    <>
      <input ref={ref} type="text" />
      <button onClick={props.onButtonClick}>Focus the input</button>
    </>
  );
})

Copy the code

useContext

Usage scenarios: useContext can be used in conjunction with React.createContext to transfer data between components.

Use the useContext mode

import React, { useRef, useContext } from 'react'; //Context, createContext receives a default const ThemeContext = react.createcontext ('white'); //Context, createContext receives a default const ThemeContext = react.createcontext ('white'); const AgeContext = React.createContext(); function Example() { return ( <> <ThemeContext.Provider value={'blue'}> <div> <ChildOfContext /> </div> Provider </ themecontext.provider > <span> I am span</span> </>); } // child component const ChildOfContext = (props) => {console.log(" inside ChildOfContext") return (<div> here is ChildOfContext <GrandChildOfContext /> </div>)} // Const GrandChildOfContext = (props) => { Console. log(" enter GrandChildOfContext") const color = useContext(ThemeContext); Return GrandChildOfContext ({color} </div>)} export default Example;Copy the code

Use the React API to modify the suntzu component as follows:

Const GrandChildOfContext = (props) => {console.log(" inside the GrandChildOfContext") < themecontext.consumer > {value => (<div> here is the child component GrandChildOfContext color is: {color} </div>)} </ themecontext.consumer >)}Copy the code

Using contextType, only React components are supported. Modify the following components:

class GrandChildOfContext extends React.Component { static contextType = ThemeContext render () { const color = This. Context return (<div> here is the child GrandChildOfContext color is: {color} </div>)}}Copy the code

Use useContext when multiple contexts are nested

import React, { useRef, useContext } from 'react'; //Context, createContext receives a default const ThemeContext = react.createcontext ('white'); //Context, createContext receives a default const ThemeContext = react.createcontext ('white'); const AgeContext = React.createContext(); function Example() { return ( <> <ThemeContext.Provider value={'blue'}> <div> <ChildOfContext /> </div> Provider </ themecontext.provider > <span> I am span</span> </>); } const ChildOfContext = (props) => {console.log(" inside ChildOfContext") return (<div>) ChildOfContext < agecontext. Provider value={21}> <div> <GrandChildOfContext /> </div> </ agecontext. Provider> </div> } // const GrandChildOfContext = (props) => {console.log(" inside GrandChildOfContext") const color = useContext(ThemeContext); const age = useContext(AgeContext); Return (<div> GrandChildOfContext color: {color} nested Context age: {age} </div>)} export default Example;Copy the code

Use the traditional React API to modify the grandson component as follows: // Use the traditional reactAPI

Const GrandChildOfContext = (props) => {console.log(" accessing GrandChildOfContext") return (< themecontext.consumer > {color} < agecontext. Consumer> {age => (<div> nested Context age is: {age} </div> )} </AgeContext.Consumer> </div> )} </ThemeContext.Consumer> ) }Copy the code

ContextType does not support nesting multiple contexts. Therefore, useContext is the simplest

Official warning: Receive a context object (the return value of react. createContext) and return the current value of the context. The current

The context value is determined by the < MyContext.provider > value prop of the upper-layer component closest to the current component. When the most recent <MyContext.Provider> update is made to the component’s upper layer, the Hook triggers a rerender and uses the latest context value passed to MyContext Provider. Even if the ancestor uses React. Memo or shouldComponentUpdate, it will be rerendered when the component itself uses useContext. Therefore, the more components that < myContext. Provider> wraps, the more nested it is, the more impact it will have on child components, resulting in unnecessary rerendering, so it is best to use Context nearby rather than across multiple levels of components

Hook usage rules

Hooks are JavaScript functions, but there are two additional rules for using them:

A Hook can only be called on the outermost layer of a function. Do not call in loops, conditional judgments, or subfunctions. You can only call a Hook in the React function component. Don’t go anywhere else

Called in a JavaScript function.

import React, { useState } from 'react'; let isName = true; Function Example() { React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component Render // Only call Hook on the outermost layer of the function. Do not call in loops, conditional judgments, or subfunctions. const [count, setCount] = useState(0); If (isName){const [name, setName] = useState(' name '); isName = false; } return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }Copy the code