0

I'm new at react-native. I'm trying to implement a little more complex calculator and I've stumbled on "unwanted" re-rendering.

Here is what I have: two functional components, the first is a Flatlist of TextInput with values, the second one is a Flatlist of Text with results.

First component stores values in an array, on each TextInput endEditing I look if the value pass the check, if so I add it to the array, then I check if the all array items have a valid value, if so I raise an event with the array.

The containing Screen, where First and Second component are, receive the First component event with the valued array, and here start the problem...

Either if I store the array in a useState for further calculations, or if I calculate the array directly and store the results in a useState for results, I get a First component re-render.

The Second component has a property where I pass the results stored in the useState results.

I understand that the Second component should rerender on "results" change, but why also the First component rerender on a simple setState for the array, or for the results?

I thought about useMemo for the First component but I get an error I can't wrap my head around.

Here code snippets: First component

export default ListInputs = ({ items = [], onChange = (parameters) => {} }) => {

  //    Each input item rendered by the Flatlist
  const InputItem = ({ item }) => {
    let values = [...items];
    
    //  On endEditing check for value validity
    //  If the whole array is OK raise the onChange for calculations
    const handleChange = (item) => {
      if (item == null) return;

      const parameter = { label: item.label, value: item.value };
      updateParameter(parameter);

      if (checkParameters()) {
        onChange(values);
      }
    };  
    
    return (
          <TextInput
            onEndEditing={(event) => { handleChange({label: item.label, value: event.nativeEvent.text,}); }}>
            {item.value}
          </TextInput>
    );
  };    
  
   return (
    <FlatList
      data={items}
      initialScrollIndex={0}
      renderItem={({ item }) => { return <InputItem item={item} />;}}
      keyExtractor={(item) => item.label}
    />
  );
};

Second component

export default ListResults = ({ items }) => {

  const ListResultItem = ({item}) => {
    return (<Text>{item.value}</Text>);
  };

  return (
    <FlatList
      data={items}
      renderItem={({item}) => { return <ListResultItem result={item} />; }}
      keyExtractor={(item) => item.label}
    />
  );
};

App containing the components:

export default function DetailScreen({ route, navigation }) {
  const [parameters, setParameters] = React.useState(initialParameters);
  const [results, setResults] = React.useState(initialResults);
  
  const onParametersChange = (parameters) => {
    setParameters(parameters);
  };
  
  const calculate = (parameters) => {
    let result = [
      //    My values calculated
    ];
    setResults(result);
  };  
  
  React.useEffect(() => {
    calculate(parameters);
  }, [parameters]);

  return (
    <View style={Styles.container}>

        <ListCoordinates
          items={initialParameters}
          onChange={onParametersChange} />

        <ListResults 
          data={results} />

    </View>
  );
}

PS: I've tried following the answer found here, but without success: functional component rerender on state change

Any suggestion is highly appreciated ^^

Andrea Celin
  • 160
  • 2
  • 8
  • try wrapping your `onParametersChange` with `useCallback`. the problem probably when the container re-render, the function `onParametersChange` re-render too, causing first component to re-render – jted95 Oct 19 '22 at 09:26
  • Hi @jted95, I've wrapped this way: const callbackParametersChange = React.useCallback((values) => { setParameters(values); },[parameters]); (where parameters is useState const, and changed the event on the First component to this onChange={callbackParametersChange} but unfortunately didn't work, sorry. – Andrea Celin Oct 19 '22 at 09:57
  • PS: I've also tried using export default React.memo(ListInputs); and export default React.memo(ListResults); to no avail... it seems that every time I use setParameters everything reloads. – Andrea Celin Oct 19 '22 at 10:09

1 Answers1

0

I'll answer my own question, found a workaround rather than a solution.

After stripping down the code to the minimum, I found out that the re-rendering is happening only when using a function to render items in FlatList.

Having the item rendered with inline code resolve the issue.

I am not sure why is this, but now I just have a huge FlatList with inline render, but at least it works.

Andrea Celin
  • 160
  • 2
  • 8