私有组件的 React.memo 与 useMemo

cri*_*zis 9 reactjs react-native

想象一下,您有一个组件需要一个函数来呈现该组件层次结构中的特定子树:

const Timeline = ({ renderDetails, ... }: { renderDetails: (rowData, sectionID, rowID) => React.Node }) => <div>{renderChildren(...)}</div>;
Run Code Online (Sandbox Code Playgroud)

使用上有区别吗:

const MyComponent = React.memo(({ someProp }) => <someComponentHierarchyHere>...</someComponentHierarchyHere>);

const ParentComponent = ({ someProp }) => {
    const renderChildren = useCallback(() => <MyComponent someProp={someProp} />, [someProp]);

    return <Timeline renderChildren={renderChildren} />;
};

Run Code Online (Sandbox Code Playgroud)

const ParentComponent = ({ someProp }) => {
    const MyComponent = useMemo(({ someProp }) => <someComponentHierarchyHere>...</someComponentHierarchyHere>);
    const renderChildren = useCallback((rowData, sectionID, rowID) => <MyComponent someProp={someProp} />, [someProp]);

    return <Timeline renderChildren={renderChildren} />;
};
Run Code Online (Sandbox Code Playgroud)

或者简单地:

const ParentComponent = ({ someProp }) => {
    const renderChildren = useCallback((rowData, sectionID, rowID) => <someComponentHierarchyHere>...</someComponentHierarchyHere>, [someProp]);

    return <Timeline renderChildren={renderChildren} />;
};
Run Code Online (Sandbox Code Playgroud)

?我特别感兴趣的是 React 渲染器将做出的决定,以及MyComponent组件(或其插入组件树中的层次结构)是否会被记忆。

eri*_*2k8 5

一般来说,组件定义应该始终是静态的,因此React.memo这里的正确选项也是如此。

如果您的内部组件是完全无状态的,useMemo则似乎可以工作,但您将无法在内部组件内部使用任何钩子,因此对于任何复杂的事情,您都必须以其他方式进行。

这样做的原因是,React 在内部跟踪在任何给定时间渲染的组件,这就是它确定由useState其他钩子返回哪些值的方式。请注意,您没有在 中使用依赖项数组useMemo,这意味着它将在每次渲染时重新创建,因此它实际上毫无意义(react hooks linting 规则会警告您这一点。但是,即使使用空的依赖项数组,它仍然在其中使用钩子是不安全的。一个常见的误解是,useMemo没有依赖项会创建一个常量,但事实并非如此。这是一种优化,通常可以防止重新计算值,但不能保证。在内部,React 可以选择useMemo随时丢弃 的记忆结果。如果发生这种情况,它会随机丢弃你的状态,所以 React 完全禁止它。

import { useMemo, useState } from 'react';

export default function App() {
  const MyComponent = useMemo(() => {
    // This line errors:
    // React Hook "useState" cannot be called inside a callback.
    // React Hooks must be called in a React function component or a
    // custom React Hook function. (react-hooks/rules-of-hooks) eslint
    const [input, setInput] = useState('')
  
    return (
      <input value={input} onChange={(e) => setInput(e.target.text)} />
    )
  })

  return <MyComponent />;
}
Run Code Online (Sandbox Code Playgroud)