很难理解删除箭头函数的价值 () =>

Gay*_*d.P 8 javascript react-native

当我在互联网上搜索react-native优化/最佳实践(特别是FlatLists通常贪婪的优化/最佳实践)时,我总是找到不要使用箭头函数的建议<Component onPress={() => ... }

\n

示例1: https ://reactnative.dev/docs/optimizing-flatlist-configuration#avoid-anonymous-function-on-renderitem :

\n
\n

将 renderItem 函数移出到 render 函数的外部,这样每次调用 render 函数时它就不会重新创建自己。(...)

\n
\n

示例 2: https: //blog.codemagic.io/improve-react-native-app-performance/

\n
\n

避免箭头函数:箭头函数是浪费重新渲染的常见罪魁祸首。不要\xe2\x80\x99t 在函数中使用箭头函数作为回调来渲染视图 (...)

\n
\n

示例 3: https: //medium.com/wix-engineering/dealing-with-performance-issues-in-react-native-b181d0012cfa

\n
\n

箭头函数是浪费重新渲染的另一个常见嫌疑点。不要在渲染函数中使用箭头函数作为回调(例如单击/点击)(...)

\n
\n

据我了解,建议不要使用箭头功能(尤其是在onPress按钮 和中FlatList),并尽可能将组件放在渲染之外。

\n

良好实践示例:

\n
const IndexScreen = () => {    \n  const onPress = () => console.log(\'PRESS, change state, etc...\')\n\n  return (\n    <>\n      <Button\n        onPress={onPress}\n      />\n      <FlatList\n        ...\n        renderItem={renderItem}\n        ListFooterComponent={renderFooter}\n      />\n    </>\n  )\n}\n\nconst renderItem = ({ item: data }) => <Item data={data} ... />\nconst renderFooter = () => <Footer ... />\n\nexport default IndexScreen\n
Run Code Online (Sandbox Code Playgroud)\n

但是,通常,我还有其他属性可以集成到我的子组件中。因此箭头函数是强制性的:

\n
const IndexScreen = () => {\n  const otherData = ...(usually it comes from a useContext())...\n\n  <FlatList\n    ...\n    renderItem={({ item: data }) => renderItem(data, otherData)}\n  />\n}\n\nconst renderItem = (data, otherData) => <Item data={data} otherData={otherData} />\n\nexport default IndexScreen\n
Run Code Online (Sandbox Code Playgroud)\n

在后一种情况下,尽管存在箭头函数,是否仍遵循良好实践?\n总而言之,如果我删除otherData(为了简单起见),这两种情况是否严格相同并且是否遵循良好实践?

\n

情况一:

\n
const IndexScreen = () => {    \n  return (\n    <FlatList\n      ...\n      renderItem={renderItem}\n    />\n  )\n}\n\nconst renderItem = ({ item: data }) => <Item data={data} ... />\n\nexport default IndexScreen\n
Run Code Online (Sandbox Code Playgroud)\n

=== 情况2?

\n
const IndexScreen = () => {    \n  return (\n    <FlatList\n      ...\n      renderItem={({ item: data }) => renderItem(data)}\n    />\n  )\n}\n\nconst renderItem = (data) => <Item data={data} ... />\n\nexport default IndexScreen\n
Run Code Online (Sandbox Code Playgroud)\n

win*_*ill 11

答案与箭头函数无关,而是理解引用相等为什么 React 可能决定重新渲染组件。

您可以使用 useCallback 来包装您的函数。这将导致对 renderItem 的引用仅在回调依赖项之一更新时更新。

const renderItem = useCallback(()=>{
...
},
[otherdata]);
Run Code Online (Sandbox Code Playgroud)

  • 这与箭头语法无关。每当 prop 或 state 的引用发生变化时,React 就会重新渲染组件。如果您在每个渲染上重新创建一个函数,然后将该新引用作为 prop 传递到子组件中,则该子组件也将重新渲染。当依赖项更新时,useCallback 只会返回对其第一个参数的新引用。在渲染循环之外创建函数(就像在模块中一样)只会创建对该函数的单个引用(或者我猜无论模块加载到何处)。 (6认同)

die*_*edu 4

第一种情况是理想的,因为当您的应用程序代码运行时,它只会创建一个renderItem函数。在第二种情况下,即使它没有 otherProps,您也没有遵循良好实践,因为此行中的每个渲染都会创建一个新函数

renderItem={({ item: data }) => renderItem(data)}
Run Code Online (Sandbox Code Playgroud)

因此,每次都要重新渲染 FlatList。

renderItem要修复它,您需要记住在prop中传递的函数useCallback

const renderItem  = useCallback(({ item: data }) => {
   return (<Item data={data} />)
}, []);

...

    <FlatList
      ...
      renderItem={renderItem}
    />
Run Code Online (Sandbox Code Playgroud)

因此,记忆版本只会在组件安装时创建一次。而且,如果您需要在渲染函数中注入更多数据,则可以将该数据定义为挂钩的依赖项,useCallback以便仅在数据更改时创建该函数,从而减少树中的重新渲染。

const renderItem  = useCallback(({ item: data }) => {
   return (<Item data={data} otherData={otherData} />)
}, [otherData]);
Run Code Online (Sandbox Code Playgroud)