React native FlatList not rerendering when data prop changes to empty array

Viewed 362

I have a FlatList with a data prop pulling from Redux

  render() {
    return (
      <View>
        <FlatList
          data={this.props.arrayOfPlacesFromRedux}
          renderItem={({item}) => {.......

Whenever I dispatch changes to arrayOfPlacesFromRedux(i.e. adding or removing children), the FlatList rerenders....UNLESS I remove all children from array (i.e. make length zero).
When arrayOfPlacesFromRedux changes from a positive length to a length of zero, the FlatList does not rerender.....however all other types of changes to array do indeed cause FlatList to rerender

UPDATE 02/27 Below is my reducer used to update Redux arrayOfPlacesFromRedux

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case UPDATE_PLACES_ARRAY:
      return {...state, arrayOfPlaces: action.payload};
    default:
      return state;
  }
};

In the situation noted above when FlatList does not rerender.....action.payload is an empty array

3 Answers

The question is missing some important piece of code. React as well as Redux need arrays reference to change, meaning for a component to reRender on state change, the array references needs to change.

Live demo at https://snack.expo.dev/RrFFxfeWY

Here is the most interesting parts:

If you have a basic component as below:


const MyList = () => {
  const [data, setData] = React.useState([
    '#FF0000',
    '#FF8000',
    '#FFFF00',
  ]);

  return (
    <>
      <Text>List poping is not working</Text>
      <FlatList
        data={data}
        renderItem={({ item }) => (
          <Pressable
            onPress={() => {
              data.pop(); // Does not work because we are not changing it's ref
            }}
            style={{ backgroundColor: item, padding: 8 }}>
            <Text>{item}</Text>
          </Pressable>
        )}
      />
    </>
  );
};

The data need to have a new array reference as below. data2.filter(..) will return a new array, we are not changing the data2 base values, just creating a new array with one item less.


const MyList = () => {
  const [data2, setData2] = React.useState([
    '#00FFFF',
    '#0080FF',
    '#0000FF',
  ]);

  return (
    <>
      <Text>List WORKING!</Text>
      <FlatList
        data={data2}
        renderItem={({ item }) => (
          <Pressable
            onPress={() => {
              setData2(data2.filter(dataItem => dataItem !== item)) // works

              //setData2([]); // Also works
            }}
            style={{ backgroundColor: item, padding: 8 }}>
            <Text>{item}</Text>
          </Pressable>
        )}
      />
    </>
  );
};

A library like Immer.js simplify the manipulation of states to mutate the object, and immer will created a new reference for you.

Oh no rookie mistake that wasted everyones time!! I was implementing shouldComponentUpdate method that was stopping Flatlist rendering :( Thanks for all for the answers

You may need to use ListEmptyComponent, which is a prop that comes with FlatList, src.

Honestly, I'm not sure why it does not re-render when you update your state, or why they added a specific function/prop to render when the array is empty, but it's clear from the docs that this is what's needed.

You can do something like this:

  <SafeAreaView style={styles.container}>
      <FlatList
        data={DATA}
        renderItem={renderItem}
        keyExtractor={(item) => item.id}
        extraData={selectedId}
-->     ListEmptyComponent={() => <MyComponent />}
      />
    </SafeAreaView>
Related