简体   繁体   中英

Append new item from database to the top of the list in component's state

I have a database listener on my app that updates my data state every time a user posts something. When I get the new post I update my state called "posts" which is an array with all the items that the FlatList renders.

The problem is that after updating the state I can't see the new post in the top of the list until I go down (to the footer of the list) and then back to the top.

My FlatList code is:

 const keyExtractor = ({id}) => id

 ...

 const renderItem = ({ item }) => {
    const {
      uri,
      description,
      location,
      width,
      height,
      likes,
      comments,
      date,
    } = item;

    return (
      <Card
        uri={uri}
        description={description}
        location={location}
        width={width}
        height={height}
        likes={likes}
        date={date}
      />
    );
  };

  return (
    <FlatList
      data={data} // data is the post state of the parent
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      initialNumToRender={15}
      windowSize={WINDOW_HEIGHT * 2}
      maxToRenderPerBatch={15}
      updateCellsBatchingPeriod={50}
      removeClippedSubviews={false}
      ListFooterComponent={
        isLoading ? (
          <View style={styles.footer}>
            <Loading type="ios" size={18} color={colors.gray} />
          </View>
        ) : null
      }
    />
  );
}

And this is how I update the post state (in the parent component of the flat list)

function Posts(props) {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    const { firebase } = props;

    let postsArray = [];

    // Realtime database listener
    const unsuscribe = firebase
      .getDatabase()
      .collection("posts")
      .doc(firebase.getCurrentUser().uid)
      .collection("userPosts")
      .orderBy("date") // Sorted by upload date
      .onSnapshot((snapshot) => {
        let changes = snapshot.docChanges();

        changes.forEach((change) => {
          if (change.type === "added") {
            // Get the new post
            const newPost = change.doc.data();

            // Add the new post to the posts list
            postsArray.unshift(newPost);
          }
        });

        // Reversed order so that the last post is at the top of the list
        setPosts(postsArray);
      });

    /* Pd: At the first time, this function will get all the user's posts */

    return () => {
      // Detach the listening agent
      unsuscribe();
    };
  }, []);

  return (
    <View style={styles.container}>
      <CardList data={posts} />
    </View>
  );
}

The issue could be caused by the way, you append new posts:

postsArray.unshift(newPost)
..
setPosts(postsArray)

It doesn't seem to affect the reference of postsArray , thus no state updates happen, no re-renders seen .

You may try, instead:

setPosts([...postsArray])

Assign a marker property extraData for telling the list to re-render (since it implements PureComponent). If any of your renderItem, Header, Footer, etc. functions depend on anything outside of the data prop, stick it here and treat it immutably.

Your update would be:

<FlatList
  data={data} 
  renderItem={renderItem}
  keyExtractor={keyExtractor}
  extraData={/* You need to create another state variable which also changes when a post is added*/}
/>

For more information visit here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM