小白篇 -- useContext 使用(结合useReducer)

175 阅读1分钟

一、先了解下 useContext 写法

index.tsx

import { useState, useContext } from 'react';

import { themes, ThemeContext } from './context';

const ContextDemo = () => {
  const [style, setStyle] = useState('light');

  const onChangeTheme = () => {
    setStyle(style === 'light' ? 'dark' : 'light');
  };

  return (
    <ThemeContext.Provider value={{ theme: themes[style], onChangeTheme }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
};

function Toolbar(props) {
  const { onChangeTheme } = useContext(ThemeContext);

  return (
    <div>
      <ThemedButton />
      <button onClick={onChangeTheme}>change</button>
    </div>
  );
}

function ThemedButton() {
  const { theme } = useContext(ThemeContext);
  console.log(theme, 'theme');
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

export default ContextDemo;

context.ts

import { createContext } from 'react';

export const themes = {
  light: {
    foreground: '#000000',
    background: '#eeeeee',
  },
  dark: {
    foreground: '#ffffff',
    background: '#222222',
  },
};

export const ThemeContext = createContext(null);

二、 结合 useReducer

index.tsx

import { useReducer, useContext } from 'react';

import { themes, ThemeContext, demoReducer } from './context';

const ContextDemo = () => {
  const [demoReducerData, dispatch] = useReducer(demoReducer, {
    theme: themes.light,
  });
  const { theme } = demoReducerData;

  return (
    <ThemeContext.Provider value={{ theme: theme, dispatch }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
};

function Toolbar(props) {
  const { dispatch } = useContext(ThemeContext);

  return (
    <div>
      <ThemedButton />
      <button
        onClick={() => {
          dispatch({ type: 'dark' });
        }}
      >
        change dark
      </button>
    </div>
  );
}

function ThemedButton() {
  const { theme } = useContext(ThemeContext);
  console.log(theme, 'theme');
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

export default ContextDemo;

context.ts

import { createContext } from 'react';

export const themes = {
  light: {
    foreground: '#000000',
    background: '#eeeeee',
  },
  dark: {
    foreground: '#ffffff',
    background: '#222222',
  },
};

export const demoReducer = (state, action) => {
  switch (action.type) {
    case 'light':
      return {
        ...state,
        theme: themes.light,
      };
    case 'dark':
      return {
        ...state,
        theme: themes.dark,
      };
    default:
      throw new Error();
  }
};

export const ThemeContext = createContext(null);

三、最后

  • 如果页面 state 很简单,可以直接使用 useState
  • 如果页面 state 比较复杂(state是一个对象或者state非常多散落在各处)请使用 userReducer
  • 如果页面组件层级比较深,并且需要子组件触发 state 的变化,可以考虑 useReducer + useContext