在 React 应用程序分析中使用备忘录重新渲染子项

in React app profiling child re-rendering with memo

在分析结果中,组件 (Table) 使用 React.memo 并且显示没有重新渲染

但下面显示了相同的 Table 组件,并且在 Why did this render 中提到父级重新渲染

Table 以这种方式使用备忘录,querystring 保持不变。

function areEqal(prevTable, nextTable) {
  return prevTable.queryString === nextTable.queryString;
}
const MemoTable = memo(Table, areEqal);
...
<MemoTable queryString={queryString} />

问题是,为什么 Table 显示两次(一次没有重新渲染,然后是)以及为什么在 querystring 更改时重新渲染。

memo只能阻止与道具相关的渲染。如果您订阅的上下文值发生变化,渲染可能仍会发生。正如评论中所讨论的,您显然使用了几个上下文,而这些正是导致渲染的原因。

虽然删除 useContexts 似乎对您的情况有效,但您没有预料到此重新呈现的事实可能表明 DataContext.provider 有一个 common mistake 其中您正在更改每个渲染器的上下文值。如果您要提供一个对象,则需要确保仅在对象的属性实际发生变化时才创建一个新对象。例如,如果您当前的代码是这样的:

const Example = ({ children }) => {
   const [userPreferences, setUserPreferences] = useState('something');

   return (
     <DataContext.Provider value={{ userPreferences, setUserPreferences }}>
       {children}
     </DataContext.Provider>
   );
}

...那么你应该像这样记住这个值:

const Example = ({ children }) => {
   const [userPreferences, setUserPreferences] = useState('something');
   const value = useMemo(() => {
     return { userPreferences, setUserPreferences }
   }, [userPreferences]);

   return (
     <DataContext.Provider value={value}>
       {children}
     </DataContext.Provider>
   );
}

至于开发工具中的两份Table,第一份是memoized组件MemoTable。 MemoTable 然后在其中呈现一个未记忆的 Table,这是第二个。 “Table (memo)”是 memo 给组件的默认名称 returns。如果您想更改该名称以使其在开发工具中显示不同,您可以:

const MemoTable = memo(Table, areEqal); 
MemoTable.displayName = "Hello world";