DAY29 - [React] useContext 实作篇

今日文章目录

  • 需求说明
  • 过程纪录
  • 问题统整
  • 重点笔记
  • 参考资料

需求说明

  • 加入深浅主题色切换。

过程纪录

  1. 深浅主题色颜色配置。

    export const theme = {
      light: {
        backgroundColor: '#eae0d0',
        color: '#000',
      },
      dark: {
        backgroundColor: '#001529',
        color: '#fff',
      },
    };
    
  2. 建立新资料夹,用来存放 Context 资料。(你可以拥有多个 Context)

  3. 使用React.createContext()方法来建立Context,并设定预设值。

    const ThemeContext = React.createContext(theme.light);
    
    export default ThemeContext;
    
  4. 使用 Context名称.Provider 来规范 资料分享范围。
    (Provider 会写入一个 value props)

    /* 
        我希望所有component都用到,所以我在 App.js 使用:
        ThemeContext.Provider 包住所有子component
    */
    
    function App() {
      return (
        <ThemeContext.Provider value={theme.light}>
          <Router>
            <Switch>
              {routes.map((item) => (
                <Route
                  key={item.path}
                  exact={item.exact}
                  path={item.path}
                >
                  {item.component}
                </Route>
              ))}
            </Switch>
          </Router>
        </ThemeContext.Provider>
      );
    }
    
  5. 子层 component 要取得 Context 资料:

     /* 引入useContext方法 与 目标Context */
     import { useContext } from 'react';
     import ThemeContext from '../context';
    
     function CategoryList(props) {
       /* 变数存取 useContext(目标Context) */
       const theme = useContext(ThemeContext);
    
       return(
         <div style={{backgroundColor: theme.backgroundColor, color: theme.color}}>
          ...
         </div>
       )
     }
    

    来解释一下:const theme = useContext(ThemeContext);

    • useContext(ThemeContext) : 接收React.createContext()回传的目标Context物件。
    ThemeContext: React.Context<{ backgroundColor: string; color: string;}>
    
    • 变数 存取 useContext()方法回传的Context值。
    theme: { backgroundColor: string; color: string;}
    

    这里的变数theme收到的值,来自 Context.Provider value props,也就是 theme.light
    这里的变数theme收到的值,来自 Context.Provider value props(theme.light)

目前显示效果:有成功套入theme.light的指定色。
theme.light浅色效果

再来做深浅色主题切换

既然资料统一放在Context,修改资料的方法也统一放在Context吧!

  1. Context.Provider 的所在元件位置,加入 useState(),并把 {state, setState} 传下去。

    function App() {
      const [themsState, setThemeState] = useState(theme.light);
    
      return (
        <ThemeContext.Provider value={{ themsState, setThemeState }}>
         ...
        </ThemeContext.Provider>
      );
    }
    
  2. 子层 component 要取得 Context 资料:

        const {state, setState} = useContext(ThemeContext);
    

    点击切换钮改值:这里使用 Antd - Switch

        <Switch
          style={{ marginTop: 10 }}
          checkedChildren="深色主题"
          unCheckedChildren="浅色主题"
          defaultChecked
          onChange={() => {
            setThemeState((pre) => (pre === theme.light ? theme.dark : theme.light));
          }}
        />
    

实现效果:
实现效果

问题统整

Q : 子层既然可以透过useContext()拿到值,那为什麽还要<Context.Provider> ?

A : useContext(MyContext) 只能让你读取 context 及订阅其变更。你仍然需要在 tree 的上层使用<MyContext.Provider> 来提供 context 的值。


Q : Context initialValue 与 Context.Provider的value props 的 差异?

A : 预设值被使用的时机是当开发者没有使用 <Context.Provider> 却又使用了 useContext 去取值时会用到;一旦使用 Context.Provider 後,就会以 <Context.Provider value={} /> 中 value 带入的值为主。

直接来验证:
Context initialValue 为 theme.light,Context.Provider value props 为 theme.dark的情况
验证


Q : 既然 Context 与 Context.Provider 可以有多组 且Context.Provider的value props会优先於Context initialValue,那要如何辨认对应的资料是拿哪一个Context.Provider?

A : 离该component最接近的 Context.Provider value props


重点笔记

All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.

这里也说明了不要滥用 useContext的原因,当 Context更新,所有范围内的子层都会 re-render,如果各种资料都往 Context 塞,将会造成效能问题。

Only use it for low-frequency updates like the theme and authentication. This is because whenever the context’s value changes, the descendant components of the Provider will be re-rendered.

Context uses reference identity to determine when to re-render.

useContext — This hook takes in a context object and returns whatever is passed in as a value prop in MyContext.Provider .


参考资料


<<:  [DAY 16] _Si7020温湿度读写

>>:  原来产品也有自己的生命历程 Product Life Cycle

Day 27: Tensorflow分类 分类图像衣物(二)

Tensorflow 衣物图像分类(二) 辅助阅读: Basic classification: C...

组译器与连结器 (上)

本文目标 理解 RISC-V 基础指令集 假指令 (pseudo instruction)、扩展指令...

家齐高中资讯研究社 社课内容2

基本建置 1.discord 开发者介面里点取newapplication 2.在Bot上点取Add...

Day#03 初始专案

前言 如同第一天所说,基本语法的练习实在是太无聊了。不如就马上来实作,从做中学吧₍₍ ◝(●˙꒳˙●...

【Side Project】 寻找日常生活中的问题

正当愁这次Side Project题目要找甚麽来做时,刚好运气不错碰到了一个随机事件。 让我决定了这...