Skip to content

GeekEast/memo-with-react-context

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Memo基础

  • 小知识: 父组件的重新渲染会引起子组件props发生改变, 所以memo默认是shallow compare
  • 何时使用: 取消父组件引起的不必要子组件渲染时
  • 针对对象: memo仅仅针对props, 不会干涉子组件的state或者store或者context引起的渲染
  • 默认比较方法: shallow compare, 修改:
import { memo } from 'react';
const myComponent = (props) => {...}
const areEqual = (prevProps, nextProps) => {...}
export default memo(MyComponent, areEqual);

SmartStrictEqual

  • 讨论前提: data is immutable
  • 注意事项: function is mutable
  • 引用比较: 针对0{}的有效
  • 浅比较: 针对只有1{}的对象有效
  • 深比较: 针对大于1{}的对象有效
import deepEqual from 'fast-deep-equal';
import { equal } from 'fast-shallow-equal';

const getType = (sth) => {
  return Object.prototype.toString.call(sth).slice(8, -1);
}

const deepObject = (obj) => {
  const keys = Object.keys(obj);
  for (let i = 0; i < keys.length; i++) {
    const type = getType(obj[keys[i]]);
    if (type === 'Object' || type === 'Array') return true
  }
  return false
}

export const smartStrictEqual = (prev, next) => {
  const prevType = getType(prev);
  const nextType = getType(next);
  if (prevType !== nextType) return Object.is(prev, next);
  if (prevType === 'Array') return deepEqual(prev, next);
  if (prevType !== 'Object') return Object.is(prev, next)
  if (deepObject(prev) || deepObject(next)) return deepEqual(prev, next)
  return equal(prev, next)
}

memo在组件Composition模式下的失效问题

组合的两种方式

  • 作为内部元素
// A的re-render会引起B的re-render
const ComponentA = () => (
  <ComponentB/>
)
  • 作为props传入
// A的re-render不会引起B的re-render
// App的re-render会引起A和B的re-render
const App = () => (
  <ComponentA>
    <ComponentB/>
  <ComponentA/>
)

两者区别

  • 内部元素: A的re-render会引起B的re-render
  • props传入:
    • App的re-render才会引起B的re-render,A不会;
    • B的re-render势必引起A的re-render, 因为B作为props传入了A
    • A使用memo是无效的,因为children中包含函数,结果一定不同

实例分析

const C0 = (props) => {
  return (
    <div>
      C0 Component
      <C1>
          <C2>
            <C3/>
          </C2>
      </C1>
    </div>
  )
}
  • 背景: 无任何memo
    • 问题: C0 re-render时, 哪些组件会跟着re-render?
    • 分析: C1, C2, C3都会re-render, 因为字面上,它们都是C0的子组件
  • 背景: 除C0外全部使用memo, 采用smartStrictEqual方法
    • 问题: C0re-render时, 哪些组件会跟着re-render?
    • 分析:
      • C3propschildren,使用memo能阻止渲染;
      • C2propschildren,memo无法阻止渲染;
      • C1propschildren, memo无法阻止渲染;
  • 解决方案:
    • 自定义比较方法,忽略对children的比较
    • 作为props的函数,在传入前要进行useCallback, 要注意添加适当的deps

Patterns

Container Pattern

  • ContainerContained之间存在数据传递
  • 灰层数据传入需要通过Container
  • ContainerContained耦合

High Order Component Pattern

  • High Order ComponentLow Order Component之间存在数据传递
  • 灰层数据传入需要通过High Order Component
  • High Order ComponentLow Order Component耦合
  • 能够优雅地多层嵌套

Render Props Pattern

  • ProviderRender Component之间存在数据传递
  • 灰层数据传入无需经过Provider层中继
  • ProviderRender Component耦合
  • 多层嵌套可以说是非常丑陋
  • 可读性很强,能够一眼看出组件间的关系

Composite Component Pattern

  • ParentChildren之间不存在数据传递
  • 灰层数据传入无需经过Provider层中继
  • ParentChildren耦合
  • 可以优雅地多层嵌套,就像HTML一样
  • 可读性强

About

Use case for using memo in React Context and Component Composition Pattern

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published