ReactNative

React memo简介

2024-02-19  本文已影响0人  半个木头人

文档:

https://zh-hans.react.dev/reference/react/memo

简介

memo (memoization)允许你的组件在 props 没有改变的情况下跳过重新渲染。

const MemoizedComponent = memo(SomeComponent, arePropsEqual?)

参数

返回值

memo 返回一个新的 React 组件。它的行为与提供给 memo 的组件相同,只是当它的父组件重新渲染时 React 不会总是重新渲染它,除非它的 props 发生了变化。

例子

在此示例中,请注意 Greeting 组件在 name 更改时重新渲染(因为那是它的 props 之一),但是在 address 更改时不会重新渲染(因为它不作为 props 传递给 Greeting):

import { memo, useState } from 'react';

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

const Greeting = memo(function Greeting({ name }) {
  console.log("Greeting was rendered at", new Date().toLocaleTimeString());
  return <h3>Hello{name && ', '}{name}!</h3>;
});

state

即使一个组件被记忆化了,当它自身的状态发生变化时,它仍然会重新渲染。memoization 只与从父组件传递给组件的 props 有关。

context

即使组件已被记忆化,当其使用的 context 发生变化时,它仍将重新渲染。记忆化只与从父组件传递给组件的 props 有关。

使用注意

最小化 props 的变化

当你使用 memo 时,只要任何一个 prop 与先前的值不是 浅层相等 的话,你的组件就会重新渲染。这意味着 React 会使用 Object.is 比较组件中的每个 prop 与其先前的值。注意,Object.is(3, 3)true,但 Object.is({}, {})false

为了最大化使用 memo 的效果,应该尽量减少 props 的变化次数。例如,如果 props 是一个对象,可以使用 useMemo 避免父组件每次都重新创建该对象:

function Page() {
  const [name, setName] = useState('Taylor');
  const [age, setAge] = useState(42);

  const person = useMemo(
    () => ({ name, age }),
    [name, age]
  );

  return <Profile person={person} />;
}

const Profile = memo(function Profile({ person }) {
  // ...
});

最小化 props 的改变的更好的方法是确保组件在其 props 中接受必要的最小信息。例如,它可以接受单独的值而不是整个对象:

function Page() {
  const [name, setName] = useState('Taylor');
  const [age, setAge] = useState(42);
  return <Profile name={name} age={age} />;
}

const Profile = memo(function Profile({ name, age }) {
  // ...
});

即使是单个值有时也可以投射为不经常变更的值。例如,这里的组件接受一个布尔值,表示是否存在某个值,而不是值本身:

function GroupsLanding({ person }) {
  const hasGroups = person.groups !== null;
  return <CallToAction hasGroups={hasGroups} />;
}

const CallToAction = memo(function CallToAction({ hasGroups }) {
  // ...
});

当你需要将一个函数传递给记忆化(memoized)组件时,要么在组件外声明它,以确保它永远不会改变,要么使用 useCallback 在重新渲染之间缓存其定义。

指定自定义比较函数

在极少数情况下,最小化 memoized 组件的 props 更改可能是不可行的。在这种情况下,你可以提供一个自定义比较函数,React 将使用它来比较旧的和新的 props,而不是使用浅比较。这个函数作为 memo 的第二个参数传递。它应该仅在新的 props 与旧的 props 具有相同的输出时返回 true;否则应该返回 false。

const Chart = memo(function Chart({ dataPoints }) {
  // ...
}, arePropsEqual);

function arePropsEqual(oldProps, newProps) {
  return (
    oldProps.dataPoints.length === newProps.dataPoints.length &&
    oldProps.dataPoints.every((oldPoint, index) => {
      const newPoint = newProps.dataPoints[index];
      return oldPoint.x === newPoint.x && oldPoint.y === newPoint.y;
    })
  );
}

疑难解答

当组件的某个 prop 是对象、数组或函数时,我的组件会重新渲染。

React 通过浅比较来比较旧的和新的 prop:也就是说,它会考虑每个新的 prop 是否与旧 prop 引用相等。如果每次父组件重新渲染时创建一个新的对象或数组,即使它们每个元素都相同,React 仍会认为它已更改。同样地,如果在渲染父组件时创建一个新的函数,即使该函数具有相同的定义,React 也会认为它已更改。为了避免这种情况,可以简化 props 或在父组件中记忆化(memoize)props

上一篇 下一篇

猜你喜欢

热点阅读