The appearance of Hook makes function components have their own state to maintain, but the parameter transmission between components is still a little complicated. Here, we use the two hooks useContext and useReducer to realize the communication between components, and can manage the global state
The directory structure
Provide global data (context.js)
The value properties injected into the provider include
- State: indicates the global status
- Dispatch: event trigger
- GetValue: Function to get state based on key
- SetValue: A function that sets state based on the key
import React, { useReducer } from 'react';
import {initState, reducer} from './reducer';
export const Context = React.createContext({});
export function ConfigContext({children}) {
const [state, dispatch] = useReducer(reducer, initState);
const getValue = (key) = > state[key];
const setValue = (key, value ) = > {
return dispatch({type: 'SET_VALUE', key, value });
}
let ctx = {
state,
dispatch,
getValue,
setValue,
};
return <Context.Provider value={ctx} >{children}</Context.Provider>
}
Copy the code
State Handling function (Reducer.js)
Provide an initial state and return the latest state.
// Initial state
export const initState = {
count: 0};export function reducer(state,{type, ... payload}){
switch(type) {
case 'SET_VALUE': {return {
...state,
[payload.key]:[payload.value],
};
}
default: {
returnstate; }}}Copy the code
Component usage (setting state values)
import React, { Fragment, useContext } from 'react';
import {Context} from '.. /context';
export default function Count() {
const {state:{count}, setValue} = useContext(Context);
return (
<Fragment>
<button onClick={()= > setValue("count", +count+1)}> + 1 </button>
<button onClick={()= > setValue("count", +count-1)}> - 1 </button>
</Fragment>
);
}
Copy the code
Component usage (get status values)
import React, { Fragment, useContext } from 'react';
import {Context} from '.. /context';
export default function Show() {
const {state:{count}} = useContext(Context);
return (
<Fragment>
<div>{' now the number is ${count} '}</div>
</Fragment>
);
}
Copy the code
index.js
import React from 'react';
import {ConfigContext} from './context';
import Count from './components/count';
import Show from './components/show';
export default function Page() {
return <ConfigContext>
<Count/>
<Show/>
</ConfigContext>
}
Copy the code
demo
Matters needing attention
This is where global state control can be achieved, but it is important to note that as long as the component that references the Context, regardless of whether the data you depend on changes, as long as the state changes, the component will be rerendered. If the data volume is large, the rendering performance will be poor. For optimization, you can use memo and other methods to optimize;
Before optimization
import React, { Fragment, useContext } from 'react';
import {Context} from '.. /context';
export default function Test() {
const {state:{id}} = useContext(Context);
return (
<Fragment>
<div>My id has not changed {id}</div>
</Fragment>
);
}
Copy the code
The optimized
import React, { Fragment, useContext } from 'react';
import {Context} from '.. /context';
const Sub = React.memo(props= > {
console.log('I'm being rendered.', props)
return (
<div>Now the id is {props. Id}</div>
);
});
export default function Test() {
const {state:{id}} = useContext(Context);
return (
<Sub id={id}/>
);
}
Copy the code