UseReducer – Basic Concepts section

UseReducer – use

UseReducer – Used with useContext

In the first article, we introduced Reducer in JavaScript and some of its characteristics. If you are not familiar with Reducer, you can read the first article.

React Hook allows state and use effects in function Components when the React Hook feature is released. There are two hooks for state management: useState and useReducer. We’ll show you how to use useReducer to manage state step by step through a series of demos.

UseState version login

Let’s take a look at the general implementation of the login page using useState:

    function LoginPage() {
        const [name, setName] = useState(' '); / / user name
        const [pwd, setPwd] = useState(' '); / / password
        const [isLoading, setIsLoading] = useState(false); // Whether to display loading, sending a request
        const [error, setError] = useState(' '); // Error message
        const [isLoggedIn, setIsLoggedIn] = useState(false); // Whether to log in

        const login = (event) = > {
            event.preventDefault();
            setError(' ');
            setIsLoading(true);
            login({ name, pwd })
                .then((a)= > {
                    setIsLoggedIn(true);
                    setIsLoading(false);
                })
                .catch((error) = > {
                    // Login failure: Error information is displayed, the user name and password are cleared, and the loading flag is cleared
                    setError(error.message);
                    setName(' ');
                    setPwd(' ');
                    setIsLoading(false);
                });
        }
        return ( 
            // Return to page JSX Element)}Copy the code

In the previous Demo, we defined five states to describe the state of the page. In the login function, a series of complex state Settings are carried out when the login succeeds or fails. You can imagine that as the requirements become more complex and more states are added to the page, more setStates are scattered all over the place, and it is easy to set up errors or omissions. Maintaining such old code is a nightmare.

UseReducer version login

Let’s see how to use useReducer to modify this code. First, a brief introduction to useReducer.

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

The useReducer accepts two arguments:

The first parameter, the Reducer function, is exactly what we introduced in our last article. Second argument: initialization state. The return values are the latest state and dispatch functions (used to trigger the Reducer function to calculate the corresponding state). For complex state operation logic, nested state objects are recommended to use useReducer.

As abstract as it sounds, let’s start with a simple example:

    // Official useReducer Demo
    // First argument: application initialization
    const initialState = {count: 0};

    // Second argument: state's reducer handler
    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();
        }
    }

    function Counter() {
        Return values: the latest state and dispatch functions
        const [state, dispatch] = useReducer(reducer, initialState);
        return (
            <>// The useReducer will return the final state according to the dispatch action and rerender Count will be triggered: {state.count} // Dispatch receives a reducer action parameter, which triggers the reducer function and updates the reducer status<button onClick={()= > dispatch({type: 'increment'})}>+</button>
                <button onClick={()= > dispatch({type: 'decrement'})}>-</button>
            </>
        );
    }
Copy the code

Use useReducer to modify the login demo.

    const initState = {
        name: ' '.pwd: ' '.isLoading: false.error: ' '.isLoggedIn: false,}function loginReducer(state, action) {
        switch(action.type) {
            case 'login':
                return {
                    ...state,
                    isLoading: true.error: ' ',}case 'success':
                return {
                    ...state,
                    isLoggedIn: true.isLoading: false,}case 'error':
                return {
                    ...state,
                    error: action.payload.error,
                    name: ' '.pwd: ' '.isLoading: false,}default: 
                returnstate; }}function LoginPage() {
        const [state, dispatch] = useReducer(loginReducer, initState);
        const { name, pwd, isLoading, error, isLoggedIn } = state;
        const login = (event) = > {
            event.preventDefault();
            dispatch({ type: 'login' });
            login({ name, pwd })
                .then((a)= > {
                    dispatch({ type: 'success' });
                })
                .catch((error) = > {
                    dispatch({
                        type: 'error'
                        payload: { error: error.message }
                    });
                });
        }
        return ( 
            // Return to page JSX Element)}Copy the code

At first glance, useReducer’s code is longer, but it is clear that the second version has better readability and we can understand the logic of state changes more clearly.

As you can see, the login function now more clearly expresses the user’s intent, starting with login, login SUCCESS, and login error. The LoginPage does not need to care about how to deal with these behaviors. That is what the loginReducer needs to care about, performance and business separation.

Another benefit is that all state processing is centralized, giving us more control over state changes and making it easier to reuse state logic change code, such as dispatch({type: ‘error’}) in other functions that also need to trigger the login error state.

UseReducer allows us to separate what from how. Dispatch ({type: ‘login’}); dispatch({type: ‘login’}); ‘logout’}), all how-related codes are maintained in reducer, and the component only needs to think about What, so that our code can be more clear like the user’s behavior.

In addition, there is another benefit. We mentioned above that Reducer is actually a pure function unrelated to UI, and the useReducer scheme makes it easier for us to build automated test cases.

conclusion

Finally, we summarize some of the main contents of this article: Using reducer scenarios

  • If you have astateIt’s an array or an object
  • If you have astateThe changes are complex, and often many states need to be changed for a single operation
  • If you want to build automated test cases to ensure the stability of the application
  • If you need to modify some state in a deep subcomponent (more on this in the next article)
  • If you have a large application, you want the UI and business to be maintained separately

This article introduces the use of useReducer to help us centrally handle complex state management. But if our page is complex, broken up into multiple layers of components, what if we trigger these state changes in the child components, like the LoginButton trigger login? In the next article, we will describe how to deal with reducer sharing of complex component tree structures.

If you have seen the thinking-in-react scenario, you may wonder, isn’t it recommended that the State should have sub-components to maintain by itself? Why do you need centralized processing?

We do not recommend putting all states together, but if you do have a number of states that need to be maintained at the page level across multiple components, you can use useReducer.

PS: Recommend two articles on React State management

  • Think -in-react/React/react/React

  • application-state-management-with-react

Finally, welcome to star our renrendai big front-end team blog. All the articles will be updated to zhihu column and Nuggets account simultaneously. We will share several high quality big front-end technology articles every week. If you like this article, please give it a thumbs-up.

Refer to the link

  • Github.com/immerjs/imm…
  • Reactjs.org/docs/contex…
  • Reactjs.org/docs/hooks-…
  • www.robinwieruch.de/react-usere…
  • www.robinwieruch.de/react-state…
  • Kentcdodds.com/blog/applic…