UseReducer – Basic Concepts section

UseReducer – use

UseReducer – Used with useContext

Welcome back to the third installment of our useReducer series. If this is the first time you’ve seen this series, we recommend you take a look at the first two:

As mentioned at the end of the previous article, using useReducer can help us centrally handle complex state management. But if our page is complex, broken down into multiple layers of components, how do we trigger these state changes in child components, such as a LoginButton failure?

This article will show you how to use another high-level hook-usecontext to solve these problems.

UseContext, as its name suggests, uses React Context as a Hook. This section describes the concept of Context and how to use it. For more information about Context, see the official documents.

The context is introduced

The following definition comes from the official documentation:

Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language. 
Copy the code

Context is a technique for providing globally shared data to the tree of components it contains.

// Step 1: Create the context you want to share
const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    // Step 2: Use the Provider to provide the value of ThemeContext. Any subtree contained by the Provider can directly access the value of ThemeContext
    return( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } // The Toolbar component does not need to transparentthemecontext function (props) {return (<div> <ThemedButton /> </div>); } function ThemedButton(props) {// use shared Context const theme = useContext('ThemeContext'); render() { return <Button theme={theme} />; }}Copy the code

Another important point about Context is that when the Context Provider’s value changes, all its child consumers rerender.

UseContext version login

After watching the above Demo, we are going back to think about how to use context to solve the reducer state changes of the descendant class components mentioned at the beginning of our question. That’s right, share the dispatch function as the value of the context to the page’s child components.

    // Define the initialization value
    const initState = {
        name: ' '.pwd: ' '.isLoading: false.error: ' '.isLoggedIn: false,}// Define the state[business] process logic reducer function
    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; }}// Define context
    const LoginContext = React.createContext();
    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 }
                    });
                });
        }
        // Use context to share dispatches
        return ( 
            <LoginContext.Provider value={dispatch}>
                <.>
                <LoginButton />
            </LoginContext.Provider>State const dispatch = useContext(LoginContext); Const click = () => {if (error) {// Action dispatch({type: 'error' payload: {error: error.message } }); }}}Copy the code

As you can see, useReducer combines useContext with the context to provide the dispatch function to all components in the component tree, instead of passing it layer by layer by adding the callback function through props.

Advantages of using Context over callbacks:

  1. The Context Api is more explicit than the custom name of the callback function, so we can know more clearly which components use dispatches, data flows and changes in the application. React has always had the advantage of one-way data flow.

  2. Better performance: If passed with a callback function, because the render function changes each time, it also causes a child component rerender. Of course, we can use useCallback to solve this problem, but it is officially recommended to use useReducer over useCallbackReact because React ensures that the dispatch is always unchanged and does not cause the consumer component to rerender.

For more information please refer to the official FQA:

how-to-avoid-passing-callbacks-down

how-to-read-an-often-changing-value-from-usecallback

conclusion

At this point, the useReducer series is over. Let’s review briefly:

  • If your pagestateIt’s very simple and can be used directlyuseState
  • If your pagestateIf the state is complicated (the state is an object or there are many scattered states) use userReducer
  • If your page component hierarchy is deep and requires sub-component triggeringstateFor changes, consider useReducer + useContext

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.

The resources

  • 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…