useContext

Consider such a scenario as the component tree mechanism shown in the figure below, inAppComponent we implement user login, and the login status needs to be used by the component, such asA, B, CComponents that need to be logged in to respond to user actions. If you are usingpropsTransparent transmission of the login state will inevitably be passed layer by layer. If the nesting level is particularly deep, this transmission is very dangerous and uncontrollable.useContext ApiCan be shown in this kind of scene its greatest effect, as follows we passcontextTransfer the content of the login state.

// login.context.ts
import React, { useContext, useEffect } from 'react';

interface IUser {
    name: string;
    age: number;
    id: string;
}

const LoginContext = React.createContext<IUser>();

export const LoginContextProvider = (props) = > {
    const [user, setUser] = useState<IUser>({});
    useEffect(() = >{(async() = > {const userinfo = await fetch('user/get');
            setUser(userinfo);
        })();
    }, []);
    return (
        <LoginContext.Provider value={user}>
            {props.childred}
        </LoginContext.Provider>
    );
};

export useLoginContext = () = > {
    return useContext(LoginContext);
};

/ / App to use
import { useLoginContext } from './login.context';
const App = () = > {
    const {name} = useLoginContext();
    
    return (
        <div>The current login user is: {name}</div>
    );
};

const AppWithContext = () = > {
    return (
        <LoginContextProvider>
            <App />
        </LoginContextProvider>
    );
};

export default AppWithContext;
Copy the code

We can use useLoginContext to get the latest user information from any node we want. This avoids the need for props to be passed through, and the component will be rerendered when the context value is updated.

useReducer

UseReducer as an alternative useState, see website https://zh-hans.reactjs.org/docs/hooks-reference.html#usereducer document detailed document. Let’s use useReducer to implement the create-React-app example again.

// App.tsx
import React, { useReducer, useCallback } from 'react';

export default const App = () = > {
    const reducer = useCallback((preState, action) = > {
        const { type } = action;
        switch(type) {
            default:
                return preState;
            case 'increment':
                return { count: preState.count + 1}; }} []);const [state, dispatch] = useReducer(reducer, { count: 0 });
    return (
        <div>
            <p>
               <button
                   type="button"
                   onClick={()= > dispatch({ type: 'increment' })}
               >
                count is: {state.count}
              </button>
        </p>
        </div>
    );
};
Copy the code

useContext + useReducer = Redux

In actual React projects, redux is used to manage some global state data, but with the use of React Hooks, useContext + useReducer can also be used to implement redux in some scenarios. In the following scenarios, we can consider using the useContext + useReducer method to achieve data sharing.

  1. Some complex components need to go deeperpropsThe data transfer
  2. The project is smaller, but it still needs to share global state data

UseContext + useReducer

  1. userReducerTo obtainstateanddispatch
  2. userContextwillstateanddispatchShare to child components
// Count.context.tsx
import React, { createContext, useCallback, Dispatch, useReducer, useContext } from 'react'

interface IState {
  count: number;
}

interface IContext {
  state: IState;
  dispatch: Dispatch<{
    type: string; payload? : Partial<IState>; } >. }const initValue: IState = {
  count: 0};const Context = createContext<IContext>({
  state: initValue,
  dispatch: () = >{}});export const ReducerContextProvider: React.FC = (props) = > {
  const reducer = useCallback((preState: IState, action: {
    type: string; payload? : Partial<IState>; }) = > {
    const { type, payload } = action;
    switch(type) {
      default:
        return preState;
        case 'increment':
          return {
            ...preState,
            count: preState.count + 1};case 'decrement':
          return {
            ...preState,
            count: preState.count - 1};case 'reset':
        return{... preState, ... payload, }; }} []);const [state, dispatch] = useReducer(reducer, initValue);

  return (
    <Context.Provider value={{state, dispatch}} >
      {props.children}
    </Context.Provider>
  );
};

export const useReducerContext = () = > {
  return useContext(Context);
};

// App.tsx
import { ReducerContextProvider, useReducerContext } from './Count.context';

const App = () = > {
    const { state, dispatch } = useReducerContext();
    
    return (
        <div>
            <p>
               <button
                   type="button"
                   onClick={()= > dispatch({ type: 'increment' })}
               >
                count is: {state.count}
              </button>
        </p>
        </div>
    );
};

const AppWithStore = () = > {
  return (
    <ReducerContextProvider>
      <App />
    </ReducerContextProvider>)}export default AppWithStore
Copy the code