最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Difficulty understanding the value of removing arrow functions () => - Stack Overflow

programmeradmin3浏览0评论

When I search the internet for react-native optimizations / best practices (Especially for FlatLists which are often greedy), I always find the advice not to use the arrow functions <Component onPress={() => ... }.

Example 1 : /docs/optimizing-flatlist-configuration#avoid-anonymous-function-on-renderitem :

Move out the renderItem function to the outside of render function, so it won't recreate itself each time render function called. (...)

Example 2 : / :

Avoid Arrow Functions : Arrow functions are a mon culprit for wasteful re-renders. Don’t use arrow functions as callbacks in your functions to render views (...)

Example 3 : :

Arrow functions is another usual suspect for wasteful re-renders. Don’t use arrow functions as callbacks (such as click/tap) in your render functions (...)

I understand that it is remended not to use arrow function (especially in onPress button and FlatList), and to put the ponents outside of the render if possible.

Good practice example :

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

But, often, I have other properties to integrate into my child ponents. The arrow function is therefore mandatory:

const IndexScreen = () => {
  const otherData = ...(usually it es from a useContext())...

  <FlatList
    ...
    renderItem={({ item: data }) => renderItem(data, otherData)}
  />
}

const renderItem = (data, otherData) => <Item data={data} otherData={otherData} />

export default IndexScreen

In the latter situation, are good practices followed despite the presence of an arrow function ? In summary, if I remove otherData (for simplicity), are these two situations strictly identical and are good practices followed ?

Situation 1 :

const IndexScreen = () => {    
  return (
    <FlatList
      ...
      renderItem={renderItem}
    />
  )
}

const renderItem = ({ item: data }) => <Item data={data} ... />

export default IndexScreen

=== Situation 2 ?

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

const renderItem = (data) => <Item data={data} ... />

export default IndexScreen

When I search the internet for react-native optimizations / best practices (Especially for FlatLists which are often greedy), I always find the advice not to use the arrow functions <Component onPress={() => ... }.

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

Move out the renderItem function to the outside of render function, so it won't recreate itself each time render function called. (...)

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

Avoid Arrow Functions : Arrow functions are a mon culprit for wasteful re-renders. Don’t use arrow functions as callbacks in your functions to render views (...)

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

Arrow functions is another usual suspect for wasteful re-renders. Don’t use arrow functions as callbacks (such as click/tap) in your render functions (...)

I understand that it is remended not to use arrow function (especially in onPress button and FlatList), and to put the ponents outside of the render if possible.

Good practice example :

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

But, often, I have other properties to integrate into my child ponents. The arrow function is therefore mandatory:

const IndexScreen = () => {
  const otherData = ...(usually it es from a useContext())...

  <FlatList
    ...
    renderItem={({ item: data }) => renderItem(data, otherData)}
  />
}

const renderItem = (data, otherData) => <Item data={data} otherData={otherData} />

export default IndexScreen

In the latter situation, are good practices followed despite the presence of an arrow function ? In summary, if I remove otherData (for simplicity), are these two situations strictly identical and are good practices followed ?

Situation 1 :

const IndexScreen = () => {    
  return (
    <FlatList
      ...
      renderItem={renderItem}
    />
  )
}

const renderItem = ({ item: data }) => <Item data={data} ... />

export default IndexScreen

=== Situation 2 ?

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

const renderItem = (data) => <Item data={data} ... />

export default IndexScreen
Share Improve this question edited Oct 18, 2021 at 14:40 Gaylord.P asked Oct 18, 2021 at 14:24 Gaylord.PGaylord.P 1,4684 gold badges28 silver badges71 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 11

The answer has nothing to do with arrow functions, but rather understanding reference equality why react might decide to rerender a ponent.

You can use useCallback to wrap your function. This will cause the reference to renderItem to only update when one of your callback dependencies updates.

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

The first situation is ideal, because when your app code runs it will create only one renderItem function. In the second situation, even if it doesn't have otherProps, you're not following the good practice because a new function is created every render in this line

renderItem={({ item: data }) => renderItem(data)}

Hence, making the FlatList rerender every time.

To fix it, you need to memoize the function you pass in the renderItem prop with useCallback

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

...

    <FlatList
      ...
      renderItem={renderItem}
    />

so the memoized version will be created only once when the ponent mounts. And, if you need to inject more data in the render function, you define that data as a dependency of the useCallback hook to create the function only when that data changes, reducing rerenders down the tree.

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

to me as pointed out previously in other answers the issue is mainly due to the fact that if you use arrow functions inside the code, the function get redefined every time. Also this way of defining a function make this function unnamed so this is harder to track while debugging: on error stack trace you can see the name of a named function directly in the code.

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

this way in the stack trace of errors you should see renderItemFunction indication

发布评论

评论列表(0)

  1. 暂无评论