useContext
Consider such a scenario as the component tree mechanism shown in the figure below, inApp
Component we implement user login, and the login status needs to be used by the component, such asA, B, C
Components that need to be logged in to respond to user actions. If you are usingprops
Transparent 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 Api
Can be shown in this kind of scene its greatest effect, as follows we passcontext
Transfer 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.
- Some complex components need to go deeper
props
The data transfer - The project is smaller, but it still needs to share global state data
UseContext + useReducer
userReducer
To obtainstate
anddispatch
userContext
willstate
anddispatch
Share 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