Skip to content

GeekEast/memo-with-react-context

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Feb 28, 2020
59f038b · Feb 28, 2020

History

11 Commits
Feb 27, 2020
Feb 27, 2020
Feb 28, 2020
Feb 27, 2020
Feb 23, 2020
Feb 27, 2020
Feb 27, 2020
Feb 27, 2020
Feb 27, 2020

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