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



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

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

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

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

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

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

箭头函数是另一个经常被怀疑浪费的重新渲染。不要在渲染函数中使用箭头函数作为回调函数(如click/tap)

我明白,建议不要使用箭头功能(特别是在onPress按钮和FlatList),如果可能的话,把组件放在渲染之外。

良好实践示例:

const IndexScreen = () => {    
const onPress = () => console.log('PRESS, change state, etc...')
return (
<>
<Button
onPress={onPress}
/>
<FlatList
...
renderItem={renderItem}
ListFooterComponent={renderFooter}
/>
</>
)
}
const renderItem = ({ item: data }) => <Item data={data} ... />
const renderFooter = () => <Footer ... />
export default IndexScreen

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

const IndexScreen = () => {
const otherData = ...(usually it comes from a useContext())...
<FlatList
...
renderItem={({ item: data }) => renderItem(data, otherData)}
/>
}
const renderItem = (data, otherData) => <Item data={data} otherData={otherData} />
export default IndexScreen

在后一种情况下,尽管存在箭头函数,但是否遵循了良好的实践?总之,如果我删除otherData(为了简单起见),这两种情况是否完全相同,是否遵循了良好的实践?

情形1:

const IndexScreen = () => {    
return (
<FlatList
...
renderItem={renderItem}
/>
)
}
const renderItem = ({ item: data }) => <Item data={data} ... />
export default IndexScreen

===情况2 ?

const IndexScreen = () => {    
return (
<FlatList
...
renderItem={({ item: data }) => renderItem(data)}
/>
)
}
const renderItem = (data) => <Item data={data} ... />
export default IndexScreen

答案与箭头函数无关,而是理解引用相等性,为什么react可能决定呈现组件。

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

const renderItem = useCallback(()=>{
...
},
[otherdata]);

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

行中每次渲染都会创建一个新函数。
renderItem={({ item: data }) => renderItem(data)}

因此,使FlatList每次都呈现。

要解决这个问题,您需要使用useCallback

来记忆您在renderItemprop中传递的函数。
const renderItem  = useCallback(({ item: data }) => {
return (<Item data={data} />)
}, []);
...
<FlatList
...
renderItem={renderItem}
/>

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

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

对我来说,正如前面在其他答案中指出的那样,问题主要是由于如果在代码中使用箭头函数,则每次都要重新定义函数。此外,这种定义函数的方式使该函数未命名,因此在调试时更难跟踪:在错误堆栈跟踪中,您可以直接在代码中看到命名函数的名称。

const renderItem  = useCallback( function renderItemFunction ({ item: data }) {
return (<Item data={data} otherData={otherData} />)
}, [otherData]);
这样,在错误的堆栈跟踪中,您应该看到renderItemFunction指示

最新更新