This article explains in detail the new features released by React after version 16.8, and makes code demonstration of some commonly used Hooks, hoping to provide some help to friends in need.

preface

This article has been posted on Github: github.com/beichensky/… Welcome to Star!

I. Hooks introduction

Hooks are new in React V16.7.0-alpha. It lets you use state and other React features outside of class. This article is to demonstrate the use of the various Hooks API. I won’t go into details about the internals here.


Ii. Hooks first experience

Foo.js

import React, { useState  } from 'react';

function Foo() {
    // Declare a new state variable named "count"
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()= > setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}

export default Foo;
Copy the code

UseState is a Hook that allows us to have its own state without using the class component, and we can modify the state to control the presentation of the UI.


Three, the two commonly used Hooks

1, useState

grammar

const [state, setState] = useState(initialState)

  • Pass a unique argument:initialState, can be a number, string, etc., can also be an object or an array.
  • Returns an array of two elements: the first element,stateVariables,setStateModify thestateValue method.

And used in classessetStateSimilarities and differences:

  • Similarities: Called multiple times during a rendering cyclesetState, the data changes only once.
  • Differences: in classsetStateIs merged while the function componentsetStateIs replaced.

Use the compare

Previously, to use the internal state of a component, you had to use the class component, for example:

Foo.js

import React, { Component } from 'react';

export default class Foo extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }

    render() {
        return (
            <div>
            <p>You clicked {this.state.count} times</p>
            <button onClick={()= > this.setState({ count: this.state.count + 1 })}>
                Click me
            </button>
            </div>); }}Copy the code

Now we can do the same with functional components. This means that state can also be used inside functional components.

Foo.js

import React, { useState } from 'react';

function Foo() {
    // Declare a new state variable named "count"
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()= > setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}

export default Foo;
Copy the code

To optimize the

Creating the initial state is expensive, so we can avoid recreating the ignored initial state by passing in a function when using the useState API.

The common way:

// Pass a value directly, and each time render executes the createRows function to get the return value
const [rows, setRows] = useState(createRows(props.count));
Copy the code

Optimized method (recommended) :

// createRows will only be executed once
const [rows, setRows] = useState(() = > createRows(props.count));
Copy the code

2, useEffect

Previously, many operations with side effects, such as network requests, UI modifications, and so on, were performed in the lifecycle of a class component such as componentDidMount or componentDidUpdate. There is no concept of these lifecycles in function components; only the element you want to render is returned. But now, there’s a place to do side effects in the function component, using the useEffect function.

grammar

useEffect(() => { doSomething });

Two parameters:

  • The first is a function that is a side effect of the first render and subsequent updates to the render.

    • This function may have a return value, and if so, the return value must be a function that is executed when the component is destroyed.
  • The second argument, which is optional, is an array containing some of the side effects used in the first function. Use to optimize useEffect

    • If you use this optimization, make sure that the array contains outer scopes that change over time andeffectAny value used. Otherwise, your code will refer to the old value from the previous rendering.
    • If you want to runeffectAnd clean it up only once (on load and unload), you can pass an empty array ([]) as the second argument. This tellsReactyoureffectIt doesn’t depend on the sourcepropsstateSo it never needs to be rerun.

While passing [] is closer to the familiar componentDidMount and componentWillUnmount execution rules, we recommend not using it as a habit, as it often results in errors.

Use the compare

Let’s say we have a requirement that the title of the document be consistent with the count count in the Foo component.

Using class components:

Foo.js

import React, { Component } from 'react';

export default class Foo extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }

    componentDidMount() {
        document.title = `You clicked The ${this.state.count } times`;
    }

    componentDidUpdate() {
        document.title = `You clicked The ${this.state.count } times`;
    }

    render() {
        return (
            <div>
            <p>You clicked {this.state.count} times</p>
            <button onClick={()= > this.setState({ count: this.state.count + 1 })}>
                Click me
            </button>
            </div>); }}Copy the code

Side effects can now be performed in function components as well.

Foo.js

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

function Foo() {
    // Declare a new state variable named "count"
    const [count, setCount] = useState(0);

    // Similar to componentDidMount and componentDidUpdate:
    useEffect(() = > {
        // Update the document title using the browser API
        document.title = `You clicked ${count} times`;
    });

    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()= > setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}

export default Foo;
Copy the code

Not only that, you can use useEffect to perform multiple side effects (you can use one useEffect to perform multiple side effects, or you can perform them separately)

useEffect(() = > {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
});

const handleClick = () = > {
    console.log('Mouse click');
}

useEffect(() = > {
    // Bind the click event to the window
    window.addEventListener('click', handleClick);
});
Copy the code

Now it looks like it’s done. But with class components, we typically remove registered events and so on in the componentWillMount lifecycle. How do you do this in a function component?

useEffect(() = > {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
});

const handleClick = () = > {
    console.log('Mouse click');
}

useEffect(() = > {
    // Bind the click event to the window
    window.addEventListener('click', handleClick);

    return () = > {
        // Remove the click event from the window
        window.removeEventListener('click', handleClick); }});Copy the code

As you can see, the first argument we pass in can return a function that is automatically executed when the component is destroyed.

Optimize useEffect

We’ve been using the first argument in useEffect, passing in a function. What about the second argument to useEffect?

The second argument to useEffect is an array containing the state value used in useEffect, which can be used as an optimization. The useEffect is executed only if the state value in the array changes.

useEffect(() = > {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
}, [ count ]);
Copy the code

If you want to simulate the behavior of componetDidMount and not componentDidUpdate, then pass a [] to the second argument to useEffect. (This is not recommended, however, as errors may occur due to omissions)


4. Other Hooks APIS

1, useContext

grammar

const value = useContext(MyContext);

Accepts a context object (the value returned from React.createcontext) and returns the current context value for that context. The current context value is determined by the prop nearest value above the calling component in the tree < myContext.provider >.

UseContext (MyContext) is equivalent to static contextType = MyContext in class, or < myContext.consumer >.

usage

Create a context in the app.js file and pass the context to the child component Foo

App.js

import React, { createContext } from 'react';
import Foo from './Foo';

import './App.css';

export const ThemeContext = createContext(null);

export default() = > {return (
        <ThemeContext.Provider value="light">
            <Foo />
        </ThemeContext.Provider>)}Copy the code

In the Foo component, use the useContext API to get the incoming context value

Foo.js

import React, { useContext } from 'react';

import { ThemeContext } from './App';

export default() = > {const context = useContext(ThemeContext);

    return (
        <div>Foo component: The current theme is {context}</div>)}Copy the code

Matters needing attention

UseContext must be an argument to the context object itself:

  • Correct:useContext(MyContext)
  • Incorrect:useContext(MyContext.Consumer)
  • Incorrect:useContext(MyContext.Provider)

UseContext (MyContext) only allows you to read the context and subscribe to its changes. You still need < myContext.provider > to use the above content in the tree to provide the value for this context.

2, useReducer

grammar

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

An alternative to useState. Accepts the Reducer whose type is (state, action) => newState and returns the current state of the reducer paired with dispatch.

UseReducer is usually superior to useState when you are dealing with complex state logic with multiple subvalues.

usage

Foo.js

import React, { useReducer } from 'react';

const initialState = {count: 0};

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return {count: state.count + 1};
        case 'decrement':
            return {count: state.count - 1};
        default:
            throw new Error();
    }
}

export default() = > {// Use the useReducer function to create the state and dispatch function to update the state
    const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <>
            Count: {state.count}
            <br />
            <button onClick={()= > dispatch({type: 'increment'})}>+</button>
            <button onClick={()= > dispatch({type: 'decrement'})}>-</button>
        </>
    );
}
Copy the code

Optimization: Delayed initialization

You can also lazily create the initial state. To do this, you can pass the init function as the third argument. The initial state is set to init(initialArg).

It allows you to extract the logic used to calculate the initial state outside the Reducer. This is also handy for resetting the state later in response to the operation:

Foo.js

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();
    }
}

export default ({initialCount = 0= > {})const [state, dispatch] = useReducer(reducer, initialCount, init);
    return (
        <>
            Count: {state.count}
            <br />
            <button
                onClick={()= > dispatch({type: 'reset', payload: initialCount})}>
                Reset
            </button>
            <button onClick={()= > dispatch({type: 'increment'})}>+</button>
            <button onClick={()= > dispatch({type: 'decrement'})}>-</button>
        </>
    );

}
Copy the code

The difference with useState

  • whenstateWhen the state value structure is more complex, useuseReducerMore advantage.
  • useuseStateTo obtain thesetStateMethod updates data asynchronously; While the use ofuseReducerTo obtain thedispatchMethod update data is synchronized.

To illustrate the second difference, in the useState example above, we add a button:

UseState Foo in js

import React, { useState } from 'react';

function Foo() {
    // Declare a new state variable named "count"
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()= > setCount(count + 1)}>
                Click me
            </button>
            <button onClick={()= >{ setCount(count + 1); setCount(count + 1); }}> < span style = "box-sizing: border-box; color: RGB (74, 74, 74)</button>
        </div>
    );
}

export default Foo;
Copy the code

If you click the button to see if you can add the data twice, you will see that the count is only increased by 1 when you click the button once.

In the example of useReducer usage above, we add a new button: foo.js in useReducer

import React, { useReducer } from 'react';

const initialState = {count: 0};

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return {count: state.count + 1};
        case 'decrement':
            return {count: state.count - 1};
        default:
            throw new Error();
    }
}

export default() = > {// Use the useReducer function to create the state and dispatch function to update the state
    const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <>
            Count: {state.count}
            <br />
            <button onClick={()= > dispatch({type: 'increment'})}>+</button>
            <button onClick={()= > dispatch({type: 'decrement'})}>-</button>
            <button onClick={()= >{ dispatch({type: 'increment'}); dispatch({type: 'increment'}); }}> < span style = "box-sizing: border-box; color: RGB (74, 74, 74)</button>
        </>
    );
}
Copy the code

Click the button to test whether it can be added twice, and it will be found that, click once, the count increases by 2. Therefore, each dispatch of an action will update data once, useReducer is indeed synchronous update data;

3, useCallback

grammar

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

The return value memoizedCallback is a Memoized callback. Pass inline callbacks and a set of dependencies. UseCallback returns a memoized version of the memory that changes only if one of the dependencies changes.

This is useful when passing a callback to an optimized sub-component that relies on reference equality to prevent unnecessary rendering (such as shouldComponentUpdate).

When using PureComponent and Memo with child components, you can reduce unnecessary rendering times for the child components

usage

  • Pass functions to child components without using useCallback

    Foo.js

    import React from 'react';
    
    const Foo = ({ onClick }) = > {
        
        console.log('Foo:'.'render');
        return <button onClick={onClick}>Foo component button</button>
    
    }
    
    export default Foo
    Copy the code

    Bar.js

    import React from 'react';
    
    const Bar = ({ onClick }) = > {
    
        console.log('the Bar:.'render');
        return <button onClick={onClick}>Bar component button</button>;
    
    };
    
    export default Bar;
    Copy the code

    App.js

    import React, { useState } from 'react';
    import Foo from './Foo';
    import Bar from './Bar';
    
    function App() {
        const [count, setCount] = useState(0);
    
        const fooClick = () = > {
            console.log('Button of component Foo was clicked');
        };
    
        const barClick = () = > {
            console.log('Button of Bar component was clicked');
        };
    
        return (
            <div style={{ padding: 50}} >
                <p>{count}</p>
                <Foo onClick={fooClick} />
                <br />
                <br />
                <Bar onClick={barClick} />
                <br />
                <br />
                <button onClick={()= > setCount(count + 1)}>count increment</button>
            </div>
        );
    }
    
    export default App;
    Copy the code

    When we click on any of the above Count Increment buttons, we will see that the console prints two outputs, and the Foo and Bar components will be rerendered. But in our current logic, Foo and Bar components don’t need to render at all

    Now we use useCallback for optimization

  • Use the optimized version of useCallback

    Foo.js

    import React from 'react';
    
    const Foo = ({ onClick }) = > {
    
        console.log('Foo:'.'render');
        return <button onClick={onClick}>Foo component button</button>;
    
    };
    
    export default React.memo(Foo);
    Copy the code

    Bar.js

    import React from 'react';
    
    const Bar = ({ onClick }) = > {
    
        console.log('the Bar:.'render');
        return <button onClick={onClick}>Bar component button</button>;
    
    };
    
    export default React.memo(Bar);
    Copy the code

    App.js

    import React, { useCallback, useState } from 'react';
    import Foo from './Foo';
    import Bar from './Bar';
    
    function App() {
        const [count, setCount] = useState(0);
    
        const fooClick = useCallback(() = > {
            console.log('Button of component Foo was clicked'); } []);const barClick = useCallback(() = > {
            console.log('Button of Bar component was clicked'); } []);return (
            <div style={{ padding: 50}} >
                <p>{count}</p>
                <Foo onClick={fooClick} />
                <br />
                <br />
                <Bar onClick={barClick} />
                <br />
                <br />
                <button onClick={()= > setCount(count + 1)}>count increment</button>
            </div>
        );
    }
    
    export default App;
    Copy the code

    If you click on the Count Increment button, you can see that the console has no output.

    If you remove useCallback or React. Memo, you can see that the corresponding component will render unnecessarily again

4, useMemo

grammar

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

Returns a memoized value. Pass the create function and the array of dependencies. UseMemo only recalculates the memoized value when one of the dependencies changes. This optimization helps to avoid expensive calculations on each rendering.

Functions passed by useMemo during rendering are run. Don’t do things you wouldn’t normally do when rendering. For example, side effects belong to useEffect, not useMemo.

usage

  • You can cache the data, something likeVuecomputed, which can be automatically recalculated based on dependency changes
  • This can help us optimize the rendering of sub-components, such as the case where there are two sub-components Foo and Bar in the App component, which are passed from the App component to the component FoopropsWhen a change occurs, the state of the App component changes and is rerendered. The Foo component and Bar component will also be rerendered. In fact, this situation is a waste of resources, we can now useuseMemoIs used by the Foo componentpropsOnly the Foo component changesrenderBar does not rerender.

Example:

Foo.js

import React from 'react';

export default ({ text }) => {
    
    console.log('Foo:'.'render');
    return <div>Foo component: {text}</div>

}
Copy the code

Bar.js

import React from 'react';

export default ({ text }) => {
    
    console.log('the Bar:.'render');
    return <div>Bar component: {text}</div>

}
Copy the code

App.js

import React, { useState } from 'react';
import Foo from './Foo';
import Bar from './Bar';

export default() = > {const [a, setA] = useState('foo');
    const [b, setB] = useState('bar');

    return (
        <div>
            <Foo text={ a} / >
            <Bar text={ b} / >
            <br />
            <button onClick={() = >SetA (' modified Foo')}> Modify the properties passed to Foo</button>
            &nbsp;&nbsp;&nbsp;&nbsp;
            <button onClick={() = >SetB (' modified Bar')}> Modifies the property passed to Bar</button>
        </div>)}Copy the code

When we click on any of the above buttons, we will see that the console prints two outputs, and components A and B will be rerendered.

Now we use useMemo for optimization

App.js

import React, { useState, useMemo } from 'react';
import Foo from './Foo';
import Bar from './Bar';

import './App.css';

export default() = > {const [a, setA] = useState('foo');
    const [b, setB] = useState('bar');

+    const foo = useMemo(() = > <Foo text={ a} / >, [a]);
+    const bar = useMemo(() = > <Bar text={ b} / >, [b]);

    return (
        <div>+ {/ *<Foo text={ a} / >
+            <Bar text={ b} / > */}
+            { foo }
+            { bar }
            <br />
            <button onClick={() = >SetA (' modified Foo')}> Modify the properties passed to Foo</button>
            &nbsp;&nbsp;&nbsp;&nbsp;
            <button onClick={() = >SetB (' modified Bar')}> Modifies the property passed to Bar</button>
        </div>)}Copy the code

When we click on different buttons, the console will only print one output, change a or B, and only one of the a and B components will be rerendered.

UseMemo (() => fn, deps)

5, useRef

grammar

const refContainer = useRef(initialValue);

UseRef returns a mutable ref object whose.current property is initialized to the passed parameter (initialValue). The returned object persists throughout the lifetime of the component.

  • In essence,useRefLike a “box” that can be in its.currentProperty maintains a variable value.
  • useRef HooksThis applies not only to DOM references. The “ref” object is a generic container, whichcurrentAttributes are mutable and can hold any value (they can be elements, objects, primitive types, or even functions), similar to instance attributes on a class.
  • useRefClosure penetration

Note: useRef() is more useful than the ref attribute. Similar to the way you use the instance field in a class, it is easy to retain any mutable values.

Note that useRef does not notify you when the content changes. Mutating the.current property does not cause a re-render. If you want to run some code when React appends or detags references to DOM nodes, you might need to use callback references.

usage

The following example shows how elements and strings can be stored in the current of the ref generated by useRef()

Example.js

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

export default() = > {// Create inputEl with useRef
    const inputEl = useRef(null);

    const [text, updateText] = useState(' ');

    // Create textRef with useRef
    const textRef = useRef();

    useEffect(() = > {
        // Store the text value in textref.current
        textRef.current = text;
        console.log('textRef. Current:, textRef.current);
    });

    const onButtonClick = () = > {
        // `current` points to the mounted text input element
        inputEl.current.value = "Hello, useRef";
    };

    return (
        <>{/* Save input ref to inputEl */}<input ref={ inputEl } type="text" />
            <button onClick={ onButtonClick} >Display text on input</button>
            <br />
            <br />
            <input value={text} onChange={e= > updateText(e.target.value)} />
        </>
    );

}
Copy the code

Click the Show Text on Input button, and you’ll see Hello useRef on the first input; Enter something in the second input, and you can see the console print it out.

6, useLayoutEffect

grammar

useLayoutEffect(() => { doSomething });

Similar to useEffect Hooks, they perform side effects. But it is triggered after all DOM updates have been completed. Can be used to perform some of the layout related side effects, such as getting the DOM element width and height, window scroll distance, and so on.

UseEffect is preferred for side effects so as not to block visual updates. For side effects that are not DOM related, use useEffect.

usage

Use is similar to useEffect. But it will be executed before useEffect

Foo.js

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

export default() = > {const divRef = useRef(null);

    const [height, setHeight] = useState(100);

    useLayoutEffect(() = > {
        // Print the height of the div when the DOM update is complete
        console.log('useLayoutEffect: ', divRef.current.clientHeight);
    })
    
    return <>
        <div ref={ divRef } style={{ background: 'red', height: height}} >Hello</div>
        <button onClick={() = >SetHeight (height + 50)}</button>
    </>

}
Copy the code

7, useImperativeHandle

In a function component, there is no instance of the component, so there is no way to call a state or method in a child component by binding an instance of the child component, as in a class component.

So in function components, how do you call the state or method of the child component from the parent component? The answer is useImperativeHandle

grammar

useImperativeHandle(ref, createHandle, [deps])

  • The first argument is the ref value, which can be passed through the attribute or used with the forwardRef

  • The second argument is a function that returns an object whose properties are mounted to the current property of the first argument ref

  • The third argument is the set of dependent elements, the same as useEffect, useCallback, and useMemo. When the dependency changes, the second argument is reexecuted, remounted to the current attribute of the first argument

usage

Note:

  • The third parameter, dependency, must be filled in as required. Any less will result in an exception to the returned object property. Any more will result in an exception to the returned object propertycreateHandlerepeat
  • A component orhookIn, for the samerefCan only be used onceuseImperativeHandle, many times, the following executionuseImperativeHandlecreateHandleThe return value replaces the one previously executeduseImperativeHandlecreateHandleThe return value

Foo.js

import React, { useState, useImperativeHandle, useCallback } from 'react';

const Foo = ({ actionRef }) = > {
    const [value, setValue] = useState(' ');

    /** * Randomly modify the value of the function */
    const randomValue = useCallback(() = > {
        setValue(Math.round(Math.random() * 100) + ' '); } []);/** * submit function */
    const submit = useCallback(() = > {
        if (value) {
            alert('Submitted successfully, user name:${value}`);
        } else {
            alert('Please enter user name! ');
        }
    }, [value]);

    useImperativeHandle(
        actionRef,
        () = > {
            return {
                randomValue,
                submit,
            };
        },
        [randomValue, submit]
    );

    / *!!!!! To return more than one property and to write it this way, UseImperativeHandle (actionRef, () => {return {submit,}}, [submit]) useImperativeHandle(actionRef, () => { return { randomValue } }, [randomValue]) */

    return (
        <div className="box">
            <h2>Function component</h2>
            <section>
                <label>User name:</label>
                <input
                    value={value}
                    placeholder="Please enter your user name."
                    onChange={e= > setValue(e.target.value)}
                />
            </section>
            <br />
        </div>
    );
};

export default Foo;

Copy the code

App.js

import React, { useRef } from 'react';
import Foo from './Foo'

const App = () = > {
    const childRef = useRef();

    return (
        <div>
            <Foo actionRef={childRef} />
            <button onClick={()= >Childref.current.submit ()}> Calls the child component's submit function</button>
            <br />
            <br />
            <button onClick={()= >ChildRef. Current. RandomValue ()} > random modify child components of the input value</button>
        </div>
    );
};

Copy the code

Try to write custom Hooks

Here we make a custom Hooks that copy the official useReducer.

1. Write a custom useReducer

Create a new usereducer.js file in the SRC directory:

useReducer.js

import React, { useState } from 'react';

function useReducer(reducer, initialState) {
    const [state, setState] = useState(initialState);

    function dispatch(action) {
        const nextState = reducer(state, action);
        setState(nextState);
    }

    return [state, dispatch];
}
Copy the code

Tip: Hooks can be used not only within function components, but also within other Hooks.

2. Use a custom useReducer

Ok, the custom useReducer is finished, let’s see if it can be used normally?

Overwrite Foo component

Example.js

import React from 'react';

// From the custom useReducer
import useReducer from './useReducer';

const initialState = {count: 0};

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return {count: state.count + 1};
        case 'decrement':
            return {count: state.count - 1};
        default:
            throw new Error();
    }
}

export default() = > {// Use the useReducer function to create the state and dispatch function to update the state
    const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <>
            Count: {state.count}
            <br />
            <button onClick={()= > dispatch({type: 'increment'})}>+</button>
            <button onClick={()= > dispatch({type: 'decrement'})}>-</button>
        </>
    );
}
Copy the code

V. Hooks use and write specification

  • Do not call Hooks from regular JavaScript functions;

  • Do not call Hooks inside loops, conditions, or nested functions.

  • Hooks must be called at the top of the component;

  • You can call Hooks from the React function component.

  • Hooks can be called from within custom Hooks.

  • It is a convention that custom Hooks must start with use.


Use the React ESLint plugin

As stated in the previous paragraph, there are certain rules to follow when using Hooks in React. However, in the process of writing code, these usage rules may be ignored, resulting in some uncontrollable errors. In this case, we can use the ESLint plugins provided by React: eslint-plugin-React-hooks. Here’s how to use it.

Install the ESLint plug-in

$ npm install eslint-plugin-react-hooks --save
Copy the code

Use plug-ins in.eslintrc

// Your ESLint configuration
// "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks
// "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies
{
  "plugins": [
    "react-hooks"]."rules": {
    "react-hooks/rules-of-hooks": "error"."react-hooks/exhaustive-deps": "warn"}}Copy the code

Vii. Reference documents

The React website

React Hooks FAQ

Write in the back

If there is a wrong or not rigorous place to write, you are welcome to put forward valuable comments, thank you very much.

If you like or help, please welcome Star, which is also a kind of encouragement and support to the author.