2

The problem: I have a FlashList that uses React Context to fill in the data (the data is an array of objects that renders a View) but when I update the context and the extraData prop for FlashList, the list does not re-render, or re-renders sometimes, or takes multiple events to actually re-render.

The Code:

// Many imports, they are all fine though

export default () => {
  // Relevant context.
  const {
    cardsArray,
    cardsArrayFiltered,
    updateCardsArray,
    updateCardsArrayFiltered
  } = useContext(AppContext);
  
  // Relevant state.
  const [didUpdateCards, setDidUpdateCards] = useState(false);
  const [cardsFilters, setCardsFilters] = useState([]);

  // Relevant refs.
  const flatListRef = useRef(null);
  
  // Example effect on mount
  useEffect(() => {
    setInitialAppState();
  }, []);
  
  // Effect that listen to changing on some data that update the context again
  useEffect(() => {
      const newCardsArray = doSomeFiltering(cardsArray, cardsFilters);
  
      updateCardsArrayFiltered(newCardsArray);
      setDidUpdateCards(!didUpdateCards);
  }, [cardsFilters]);
  
  // Example of promisey function that sets the initial context.
  const setInitialAppState = async () => {
    try {
      const newCardsArray = await getPromiseyCards();
  
      updateCardsArrayFiltered(newCardsArray);
      updateCardsArray(newCardsArray);
    } catch ( err ) {
      console.debug( err );
    }
  }
  
  // Renderer for the list item.
  const renderListItem = useCallback((list) => <Card key={list.index} card={list.item} />, []);
  
  // List key extractor.
  const listKeyExtractor = useCallback((item) => item.id, []);
  
  return (
    <FlashList
      ref={flatListRef}
      data={cardsArrayFiltered}
      extraData={didUpdateCards}
      keyExtractor={listKeyExtractor}
      renderItem={renderListItem}
      showsVerticalScrollIndicator={false}
      estimatedItemSize={Layout.window.height}
    />
  );
}

Notes:

  • What I did not write all out is the function, logic, view to update cardsFilters however the above effect IS running when it changes.
  • Moreover, this line here, const newCardsArray = doSomeFiltering(cardsArray, cardsFilters); does indeed return the proper updated data.

What's going on here? I am updating the extraData prop with that didUpdateCards state when the context changes which I thought was the requirement to re-render a FlatList/FlashList.

3 Answers 3

2

@Staghouse your component contains key property, and official docs recommend to remove it: https://shopify.github.io/flash-list/docs/fundamentals/performant-components/#remove-key-prop :

"Using key prop inside your item and item's nested components will highly degrade performance.

Make sure your item components and their nested components don't have a key prop. Using this prop will lead to FlashList not being able to recycle views, losing all the benefits of using it over FlatList."

Hope this helps.

1

It looks like object being passed as extraData is a boolean. This means that if the previous value was true, setting it as true again wouldn't count as a change. Instead use an object and update it when you want list to update.

To try just set extraData={{}}. if everything works as expected it means that your update logic has some problem.

0

Try using Shallow Copy when you update data

Not the answer you're looking for? Browse other questions tagged or ask your own question.