admin管理员组

文章数量:1336728

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.

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.

Share Improve this question asked Dec 26, 2022 at 21:38 StaghouseStaghouse 3072 silver badges15 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 4

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

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

Make sure your item ponents and their nested ponents 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.

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.

Try using Shallow Copy when you update data

本文标签: javascriptReact NativeContextFlashList wont rerender with Context updateextraData updatingStack Overflow