Shopify / flash-list

A better list for React Native
https://shopify.github.io/flash-list/
MIT License
5.53k stars 283 forks source link

MasonryFlashList doesn't always add new columns when data is added #927

Open laurence79 opened 1 year ago

laurence79 commented 1 year ago

Current behavior

https://github.com/Shopify/flash-list/assets/8775228/14f98286-bdde-48d5-b50c-e1c82ab48867

If numColumns={3} and MasonryFlatList is initially rendered with one item, when you add further items the additional necessary columns are not rendered. This is on all platforms

On iOS and Android, this happens if you start with 0 or 1 item, and use 2, 3, 5, or 6 as numColumns (4 works)

Expected behavior

Columns will be added for the new items.

To Reproduce

Reproduction: https://snack.expo.dev/@mrhartgill/masonry-layout-2nd-item-issue.

Platform:

Environment

This snack uses v1.4.0 because of the Expo SDK limitation, but I've reproduced the same thing with v1.6.1 locally.

laurence79 commented 1 year ago

Related #876, #627

tanlucvo commented 1 year ago

I have solution but I dont think it is the best solution, just change numColumns to double and each column flex is 2, have the same result

numColumns={6}
getColumnFlex={(items, index, maxColumns, extraData) => {
  return 2;
}}
alex-trofimov commented 10 months ago

Also experiencing this issue with MasonryFlashList on 1.6.3

juanch0x commented 9 months ago

I know that's not a good solution, but it end up working for my just adding a key and force a rerender when the origin length changes

<MasonryFlashList
      showsVerticalScrollIndicator={false}
      data={deals}
      key={deals.length}
      keyExtractor={(item) => `${item.business_id}__${item.id}`}
      renderScrollComponent={ScrollView}
....../>
anhChillLe commented 4 months ago

I don't think changing key is good for rendering

  const key = `note-list-${notes.length >= numColumns}`

  return (
    <AnimatedMasonryNoteList
      key={key}
      data={notes}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      extraData={extraData}
      removeClippedSubviews
      numColumns={numColumns}
      contentContainerStyle={styles.list_content}
      estimatedItemSize={200}
      {...props}
    />
  )

Or you can add a null item to data if data.length < column and check null in render item

  const data = useMemo(() => {
    if (notes.length >= numColumns) {
      return notes
    } else {
      return [...notes, null]
    }
  }, [notes, numColumns])

  return (
    <AnimatedMasonryNoteList
      data={data as Note[]}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      extraData={extraData}
      removeClippedSubviews
      numColumns={numColumns}
      contentContainerStyle={styles.list_content}
      estimatedItemSize={200}
      {...props}
    />
  )
  const renderItem: MasonryListRenderItem<Note> = ({ item, columnIndex }) => {
    if (item === null) {
      return null
    }
jerryphm commented 2 months ago

facing same issue here, any update? in my case, numColumn=2 and going from 1 item to 2 items does not render the second one

CrazyStoneJy commented 1 month ago

facing same issue here, any update? in my case, numColumn=2 and going from 1 item to 2 items does not render the second one

same bug on 1.7.0