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