DAY30 - [React] useMemo 与 後续

今日文章目录

  • 前言
  • useMemo()
  • 实作纪录
  • 参考资料
  • 後续

今天要练习 useMemo(),不过爬了很多文,觉得还无法好好消化,这篇主要纪录一些我找到的资料笔记,还有练习的过程。开始吧!

前言

昨天我们在切换页面的时候,透过Provider value props把{state, setState}传下去,让子层可以改值。

// Provider 传值与方法:
function App() {
  const [themsState, setThemeState] = useState(theme.light);

  return (
    <ThemeContext.Provider value={{ themsState, setThemeState }}>
    ...
    </ThemeContext.Provider>
  );
}

export default App;
function CategoryList(props) {
   const { themsState, setThemeState } = useContext(ThemeContext);
   return (...)
}

console.log()看一下,会发现:Provider传什麽,useContext()就会回传什麽(就是最新值)。
Provider传什麽,useContext()就会回传什麽(就是最新值)

官方文件有提到以下情况:
Caveats

我想确定目前写法:<Context.Provider value ={{state, setState}}></Context.Provider>会不会造成上述的问题。搜了一轮资料,决定用useMemo inside Context API - React的方法来测试看看。

为了做个测试,我分别在父层ToDoPage,子层CategoryList TodoList component内加入 console.log(),来确认一下使用useMemo()与没有使用useMemo()的差异。


测试目标:当我在 ToDoPage点击按钮更新值时,Provider props value 是否会重新建立,导致子层 CategoryList ToDoList re-render?

  • 对比项目:
    • CategoryList 父层加入 ThemeContext.Provider value props :
      使用 useMemo(),当 dependency改变时,才更新回传值。
    • ToDoList 父层加入 ThemeContext.Provider value props :
      直接传入{ themsState, setThemeState }

测试A

测试A

export default function ToDoPage() {
  const [forceRender, setForceRender] = useState(false);
  const [themsState, setThemeState] = useState(theme.light);
  const themeContextProvider = useMemo(() => (
      { themsState, setThemeState }), [themsState, setThemeState]
  );

  return (
    <>
      {console.log('hey! I am in ToDoPage.')}
      <MainLayout
        menu={(
          <ThemeContext.Provider value={themeContextProvider}>
            <CategoryList />
          </ThemeContext.Provider>
        )}
        content={(
          <ThemeContext.Provider value={{ themsState, setThemeState }}>
            <ToDoList />
          </ThemeContext.Provider>
        )}
      />
      <Button onClick={() => setForceRender(!forceRender)}>Rerender Parent</Button>
    </>
  );
}

显示效果:

  • ToDoListCategoryList 切换 theme,更新ThemeContext.Provider值。
    ToDoList 或 CategoryList 切换 theme,更新ThemeContext.Provider值。

  • ToDoPage 点击按钮: 触发 ToDoPage CategoryList ToDoList re-render。
    ToDoList 或 CategoryList 切换 theme,更新ThemeContext.Provider值。

疑?看不出来 useMemo() 的效果


测试B :

测试B

  • CategoryList、ToDoList 加入 memo()
    试试看!
export default memo(CategoryList);
export default memo(ToDoList);

显示效果:

  • ToDoListCategoryList 切换 theme,更新ThemeContext.Provider值。
    ToDoList 或 CategoryList 切换 theme,更新ThemeContext.Provider值。

  • ToDoPage 点击按钮: 触发 ToDoPage ToDoList re-render。CategoryList 没有。
    ToDoPage 点击按钮: 触发 ToDoPage ToDoList re-render。CategoryList 没有

呼~终於有点收获...

目前看起来的状况:
测试A:父层状态改变,子层re-render。
测试B:父层状态改变,透过memo()比对CategoryList ToDoList,根本没有props,所以不受父层状态改变影响,唯一带来改变的是ToDoListThemeContext.Provider value={{ themsState, setThemeState }},每次都重新建立。

不过我应该把 console.log() 放一个在 useMemo()比较准才对..


useMemo 小百科:

useMemo(() => computeExpensiveValue(a, b), [a, b]);

  • 为了解决当元件本身改变状态 re-render,避免元件内无关的逻辑重复渲染的效能问题。
  • 用途:当dependency改变,才会执行computeExpensiveValue(a, b)重新计算,回传一个 memoized 的值。
  • 参数:
  • computeExpensiveValue(a, b) : 一function,回传值会让React记着,在dependency没改变的情况下,会一直沿用该回传值。
  • [a, b]: dependency。

memo 小百科:

memo(MyComponent, areEqual) :
React 渲染机制,只要父层state改变,不论子层接收的props值是否有改变,子层一律强迫 re-render。
memo()是为了解决子层接收的props导致重复渲染的效能问题。

  • 用途:比对 更新前後props差异,没有改变,会跳过这次 re-render。
  • 参数:
    > MyComponent : 作用元件
    > areEqual *(optional)* : 客制function。memo()比对方式 shallowly compare complex objects in the props object,如果要做更深层的比对,可以自己写。
  • If your function component wrapped in React.memo has a useState, useReducer or useContext Hook in its implementation, it will still rerender when state or context change. - 节录React 官网。

杂记

  • useXXX comparison: Object.is(value1, value2)

React uses the Object.is comparison algorithm.


参考资料


後续

哇~真的把30天撑完了,好感动喔
10天React练习让我有机会重新再回来看React 文件,我记得我刚开始接触的时候,真的是有看没有懂...目前写了半年多,回来看文件会发现以前看不懂的,现在渐渐能理解它的意思,还有很多需要再练习,但觉得满足。感谢铁人赛!

这10天只有写到一小部分,回头看自己的文章,有些知识漏洞。之後会继续补齐 use系列,不会一天一po,等我练到有点心得再继续跟大家分享,恭喜各位铁人完赛,下次见罗!


<<:  【後转前要多久】# Day15 CSS -难东西 (伪元素)

>>:  # Day 21 Heterogeneous Memory Management (HMM) (一)

认识强大的Python套件:NumPy

昨天已经学会要如何呼叫套件了,今天就让我们来学习套件里的语法运用吧! 首先先呼叫我们的NumPy套件...

[Day 22] SQL inner join

join 利用栏位的关联性,将不同的资料表串连起来。 students 资料表 s_id name ...

YouTube 推动全球电信商建立私有云

高级技术架构师 Frederic Lhoest 在网上发现了指导视频和案例研究,这些信息和案例研究...

Progressive Web App Checklist: 优化检核清单项目说明 (7)

Starts fast, stays fast Web App 的效能会直接影响使用者体验,也会影响...

[Lesson8] MediaPlayer

activity_main: 在LinearLayout中加入播放/暂停、停止、循环的按钮 <...