简体   繁体   中英

Fail to prevent re-render by React.memo

I am building a react native app for which has a form page contains a lot of textInput and buttons. Each of fields do not causing performance issue.

However, when they are put together, the application will show js thread frame drops in the Perf Monitor. So I think the page is re-rendering all the components when any of the state is changed.

I tried 2 methods.

  1. Moving components out of the main export function.
  2. Using React.memo .

Unfortunately, both of them are not working. The app still lag and re-render every time for all components.

So I created a simple case for it. You may see the code below.

I would like to only re-render the ChildItem for only the respective state changed. For now, console will log from 1 to 5 for any button clicked. Since the props passed to memo component is not changed, I expect the console will only log 1 respective sentence for specific index when button is pressed.

import React, {useState, memo} from 'react';
import { View, Text, Button } from 'react-native';

const ChildeItem = memo( ({index, value, onPress}) =>{
  console.log(`ChildeItem ${index} rendered`);
  return(
    <View style={{flexDirection: 'row'}}>
      <Text style={{flex: 1, textAlign: 'center'}}>
        {value}
      </Text>
      <View style={{flex: 1}}>
        <Button 
          onPress={onPress} 
          title={"+"}
        />
      </View>
    </View>
  )
});

export default function TestScreen({navigation}) {
  const [value1, setValue1] = useState(0);
  const [value2, setValue2] = useState(0);
  const [value3, setValue3] = useState(0);
  const [value4, setValue4] = useState(0);
  const [value5, setValue5] = useState(0);

  return(
    <View>
      <ChildeItem index={1} value={value1} onPress={()=>{setValue1(value1+1);}} />
      <ChildeItem index={2} value={value2} onPress={()=>{setValue2(value2+1);}} />
      <ChildeItem index={3} value={value3} onPress={()=>{setValue3(value3+1);}} />
      <ChildeItem index={4} value={value4} onPress={()=>{setValue4(value4+1);}} />
      <ChildeItem index={5} value={value5} onPress={()=>{setValue5(value5+1);}} />
    </View>
  )
}

Or I have any misunderstanding for React.memo ? Any help will be appreciated. Thanks.

Your index and value props are ok for memoization, but your onPress prop causes re-render because on every render of the TestScreen, your onPress prop functions are re-created, so it's reference changes. You can prevent this by usinguseCallback hook.

export default function TestScreen({navigation}) {
  const [value1, setValue1] = useState(0);
  const [value2, setValue2] = useState(0);
  const [value3, setValue3] = useState(0);
  const [value4, setValue4] = useState(0);
  const [value5, setValue5] = useState(0);

  // Use useCallback for each function
  const onPress1 = useCallback(() => setValue1(value1+1), [value1]);
  const onPress2 = useCallback(() => setValue2(value2+1), [value2]);
  const onPress3 = useCallback(() => setValue3(value3+1), [value3]);
  const onPress4 = useCallback(() => setValue4(value4+1), [value4]);
  const onPress5 = useCallback(() => setValue5(value5+1), [value5]);

  return(
    <View>
      <ChildeItem index={1} value={value1} onPress={onPress1} />
      <ChildeItem index={2} value={value2} onPress={onPress2} />
      <ChildeItem index={3} value={value3} onPress={onPress3} />
      <ChildeItem index={4} value={value4} onPress={onPress4} />
      <ChildeItem index={5} value={value5} onPress={onPress5} />
    </View>
  )
}

By using useCallback hook, you're memoizing the onPress functions, so they are re-created only when the relevant value changes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM