1. What are Hooks

Use state and other React features without writing a class (lifecycle)

The rules

  • Do not call hooks in loops, conditions, or nested functions; React saves and reads data sequentially depending on the execution of the hooks each time the component is rendered. Hooks keep track of the order in which the calls were made, as well as the incoming and outgoing arguments, and if the order is incorrect, the corresponding return values will fail on re-rendering.
  • Do not call a Hook in a normal JS function. A Hook can only be called from the React function component, or from other custom hooks.
  • Custom Hooks are declared starting with use

State Hooks

Function components use the state-like functionality of the class component. Functional component internal state management, and component updates. It’s an asynchronous update

import React, { useState } from "react"; export default function UseState() { const [count, setCount] = useState(0); Return (<div> <p> useState</p> <h2> <button onClick={() => {setCount(count + 1); }} > </button> </div>); }Copy the code

What does useState do

The “state” registered with useState and the change method are retained by React and will not be destroyed when the function component exits.

UseState into arguments

Input parameter: the value required for initialization of “state” | or a pure function that returns the initialized value

UseState out and

Output argument: is an array.

  • The first value is the assignment result of the initialization of “state” (similar to this.state.xxx) for subsequent evaluation and presentation in components or functions.
  • The second value is the method that modifies the “state” (similar to this.setstate).

The setState method for modifying state can be used in two ways

  • SetState (state+1)
  • Method 2: Use functional update, so as to avoid using it in some cases when the exact value of state cannot be directly obtained. For example, in useEffect, the exact value setState(s=> S +1) can never be obtained because state is closed because it does not want to specify state as a dependency and needs to be modified.
// If method 1 is called multiple times in a row, it will only be executed once. But method two works every time. const [count,setCount] = useState(0); if (way === "newState") { setCount(count + 1); setCount(count + 1); setCount(count + 1); setCount(count + 1); setCount(count + 1); Count = count + 1} else if (way === "func") {setCount((s) => s + 1); setCount((s) => s + 1); setCount((s) => s + 1); setCount((s) => s + 1); setCount((s) => s + 1); Count = count + 5}Copy the code

How to use multiple state variables

  • Method 1: Multiple states, multiple declarations. Because variables and functions come in pairs, they can be easily distinguished. const [state1,setState1] = useState(0); const [state2,setState2] = useState(2); const [state3,setState3] = useState(3);

  • Method 2: Manage related data in one object. However, it is not recommended to put all data into one object. Because useState won’t help you merge, just replace. const initState = { state1:’haha’, state2:’hehe’ } const [mixState,setMinState] = useState(initState); setMixState({state1:’heihei’}); // There is no state2 setMixState({… mixState,state1:’heihei’});

    Therefore, try to put the related data in a state, but the data with little correlation will be put together, especially in the complex data structure for data update.

Effect Hooks

Function component, use the class in the component life cycle (componentDidmount/componentUpdate) life cycle, such as convenient components in function for rendering Can subscribe/unsubscribe message in the rendering process etc. UseEffect is asynchronous and does not block the browser update screen. If you need to measure a synchronization Effect like a screen, you can use useLauoutEffect. When multiple Useeffects occur, they are called in sequence according to the order in which they are declared.

import React, { useState, useEffect } from "react"; export default function UseEffect() { const [count, setCount] = useState(0); ComponentDidMount and componentDidUpdate: Document. title = 'You clicked ${count} times'; useEffect() => {document.title =' You clicked ${count} times'; }); <button onClick={() => setCount(count + 1)}> click </button> </div>; }Copy the code

Effects that need to be cleared

As with ComponentWillUnmount, bound listening events, or timers, need to be cancelled when the component is unmounted to prevent memory leaks. UseEffect is also allowed to be called as a clean Effect by returning an executable function in the passed function.

UseEffect (()=>{console.log(' render every time '); Return ()=>{console.log(' execute when uninstalled '); }});Copy the code

Note: Effect is executed on every render. However, when the current effect is executed, the previous effect is actively cleared and the executable function returned from the function is actively executed. Because an effect may be bound every time it is rendered, if the previous listener is not cancelled, it can lead to listener confusion or even repeated listening.

For example: Simulate a function component rendering update //Mount FuncComponent to perform effect, add a listener // Update FuncComponent to perform clean effect, remove the last listener to perform effect, add a listenerCopy the code

If this is not done, the same component on the page is re-registered with each update without removing the original listener. This can be buggy!

Similarly, if our useEffect performs an operation that does not need to be called again, we can skip it with the second argument. Similar to componentDidUpdate, you can check prevState,prevProps to determine whether to perform the update. UseEffect, which can also be used as an array of parameters to compare, is an optional second parameter that tells React if it needs to be executed again in the render.

UseEffect useEffect(()=>{console.log('counter 'becomes: ',props.updateTimes) },[parseInt(props.updateTimes/5)]);Copy the code

If you want to execute effect once (only when the component is mounted and unmounted), you can pass an empty array ([]) as the second argument. This tells React that your effect doesn’t depend on any value in props or state, so it never needs to be repeated. This is not a special case — it still follows the way dependent arrays work.

Custom Hooks

If the function name begins with “use” and calls other hooks, we say it is a custom Hook. The same custom Hooks are called in each function component, but the values returned by custom Hooks in each function component are separate and not shared. It’s like encapsulating a set of Hooks together and calling them directly. This is no different from calling directly from a function component.

Function useCustomReducer(reducer, initState) {const [state, setState] = useState(initState); function dispatch(action, payload) { const newState = reducer(action, state, payload); setState(newState); } return [state, dispatch]; }Copy the code

Other Hooks

useContext

  const value = useContext(MyContext);
Copy the code

Receives a context object (the return value of React. CreateContext) and returns the current value of the context. The current 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.

useReducer

  const [state,dispatch] = useReducer(reducer,initialArg,initState)
Copy the code

Parameters:

  • The reducer pure function receives an action(a string that determines which update operation to perform), a change value, and returns a new state
  • The initialArg pure function takes initState and returns an operation state, which is ultimately the initial state
  • InitState Indicates the default state. If there is no second parameter and only initState is passed, it is directly used as the initialization state

useMemo

  const memoizedValue = useMemo(() =>   
           computeExpensiveValue(a, b), [a, b]);
Copy the code

Returns an memoized value computed from the first function, which requires that the first argument be a pure function and must have a return value.

You pass in the create function and the dependency array as arguments to useMemo, which recalculates memoized values only when a dependency changes. This optimization helps avoid costly calculations every time you render.

Remember that functions passed into useMemo are executed during rendering. Please do not perform non-rendering operations inside this function. Operations such as side effects are used by useEffect, not useMemo. If the dependency array is not provided, useMemo evaluates the new value each time it renders.

useCallBack

  const memoizedCallback = useCallback(
    () => {
      doSomething(a, b);
    },
    [a, b],
  );
Copy the code

Returns an Memoized callback function, which is used the same way, except that the function and its corresponding dependencies are cached. As long as the function dependency does not change, passing to the child does not cause unnecessary updates to the child because the parent receives the function as a new object.

Passing the inline callback function and the array of dependencies as arguments to useCallback returns the Memoized version of the callback function, which is updated only when a dependency changes. This is useful when you pass callback data to child components that are optimized and use reference equality to avoid unnecessary rendering (such as shouldComponentUpdate). UseCallback (fn, deps) is equivalent to useMemo(() => FN, deps).

In contrast to useMemo, useMemo caches a value. UseCallback caches a function, which caches the value of a single props. The memo caches the component itself, which is optimized globally

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

function parent(){ const childRef = useRef(null); Return (<> <Child ref={childRef} /> <button onClick={()=>{console.log(childref.current)}} > Obtain the Child component </button> </>)} class child extends Components{ return <>haha</> }Copy the code

2. Get a DOM element from the component.

const inputRef = useRef(null);
<input ref={inputRef} type="text" />
Copy the code

3. Use it as a global variable for a component. The useRef return object contains a current property that is not repeated for the entire component color life cycle, just as the React class inherits the this.xxx property from the component.

Const isClick = useRef(false); console.log(isClick.current); Const complexObjectRef = useRef(null); function getComplexOebjct{ if(! complexObjectRef.current){ complexObjectRef.current = new ComplexObject(); } return complexObjectRef.current; } const complexObject = getComplexOebjct();Copy the code

useImperativeHandle

useImperativeHandle(ref, createHandle, [deps]);
Copy the code

The ginseng

  • Ref: Defines the ref of the current object

  • CreateHandle: a function that returns an object, the current of this ref

  • [DEPS] : the dependency list. UseImperativeHandle reprints the instance properties of the child component to the parent component when the listening dependency changes

    With react. forwadRef, this returns a modified Ref from the child, which is passed back to the parent so that the parent can check for partial value changes.

import React, { useRef, useState, useImperativeHandle } from "react"; const Child = React.forwardRef((props, ref) => { const inputRef = useRef(null); const globalAttr = useRef(0); const [clickTime, setClickTime] = useState(0); useImperativeHandle(ref, () => { return { globalAttr, addClickTime: () => { setClickTime(clickTime + 1); }, focus: () => { inputRef.current.focus(); }}; }); Return (<div> <p> parent clickTime: {clickTime}</p> <p> {globalAttr.current}</p> <input ref={inputRef} type="text" /> <button onClick={() => { globalAttr.current += 1; }} > Update child component global </button> </div>); }); export default function UseImperativeHandle() { const childRef = useRef(null); return ( <> <Child ref={childRef} /> <button onClick={() => { childRef.current.focus(); }} > get child node input box focus < / button > < button onClick = {() = > {childRef. Current. AddClickTime (); }} > add child components add value < / button > < button onClick = {() = > {the console. The log (childRef. Current. GlobalAttr); }} > Output sub-component global variable </button> </>); }Copy the code

useLayoutEffect

The use method is consistent with useEffect. The callback function in useLayoutEffect executes immediately after the DOM update is complete, but runs before the browser can do any drawing, blocking the browser’s drawing. But it is a side effect that blocks updates to browser renderings before rendering, and is typically used for operations that require changes or DOM retrieval.

useDebugValue

For development purposes, the formal environment is useless

The code address