Невозможно отобразить коллекцию данных, успешно извлеченных из базы данных с помощью ловушки реакции - PullRequest
1 голос
/ 08 февраля 2020

Я извлекаю коллекцию документов из firebase, а затем передаю ее в состояние, чтобы при ее обновлении реагировал на нее повторно,

    const [posts, setPosts] = useState([])

    const fetchPosts = () => {
        firebase.firestore().collection('posts').get()
            .then(snap => {
                snap.docs.forEach(doc => {
                    setPosts([...posts, doc.data()])
                    console.log(doc.data())
                })
            })
    }



    useEffect(() => {
        fetchPosts()
    }, [])

Я также передавал это состояние другим компонентам, чтобы они -рендеринг с обновленным состоянием

Но реакция - это только рендеринг первой команды do c и выдача в консоли ошибки: «каждый дочерний элемент должен иметь уникальный ключ prop». Каждый объект do c имеет уникальный идентификатор внутри, и я передаю его в качестве ключа для каждого сообщения

    <div className="posts section">
        {posts.map(post=>{
            return <Link to={'/posts/'+post.id}><PostCard  post={post} key={post.id} /></Link>
        })}
    </div>

Ответы [ 2 ]

1 голос
/ 11 февраля 2020

Google не рекомендует использовать данные документа / массива в качестве ключа, поскольку последующие рендеры могут быть неэффективными. Прекрасная функция React может позаботиться о проблеме уникального ключа.

<div className="posts section">
    {React.Children.toArray(
      posts.map(post => {
        return (
          <Link to={"/posts/" + post.id}>
           <PostCard post={post} />
          </Link>
        );
      })
    )}
</div>

Другая проблема, с которой вы можете столкнуться, это useEffect, ДОЛЖНО быть синхронным. Вы можете явно объявить fetchPosts как асинхронный. Я использую следующее для обработки querySnapshot:

  return query
    .get() //get the resulting filtered query results
    .then(querySnapshot => {
      return Promise.resolve(
        querySnapshot.docs.map(doc => {
          return {
            ...doc.data(),
            Id: doc.id,
            ref: doc.ref
          };
        })
      );
    })

Лучшая причина для .map заключается в том, что вы не можете гарантировать, что last"setPosts" действительно завершится до следующего l oop Таким образом, ваше состояние (в данном случае "posts") может быть устаревшим.

Итак, net всего этого, мой шаблон будет:

   const [posts, setPosts] = useState([])

    const fetchPosts = () => {
        return firebase.firestore().collection('posts').get()
        .then(snap => {
            snap.docs.map(doc => {
                console.log(doc.data())
                return {
                   ...doc.data(),
                   id: doc.id,
                   ref: doc.ref
                };
            })
        });
    }

    useEffect(() => {
        (async () => {
            const newPosts = await fetchPosts();
            setPosts(newPosts);
        })();
    }, [])

    //[etc, etc]

    return
    //[etc, etc]

        <div className="posts section">
        {React.Children.toArray(
            posts.map(post=>{
                return <Link to={'/posts/'+post.id}><PostCard  post={post} key={post.id} /></Link>
            })
        }
        </div>
0 голосов
/ 08 февраля 2020

Добавьте ключевую подпорку к компоненту Link.

Пример

const fetchPosts = () => {
    firebase
      .firestore()
      .collection("posts")
      .get()
      .then(snap => {
        let docs = [];
        snap.docs.forEach(doc => {
            docs.push(doc.data());
        });
        setPosts( prevState => [...prevState, ...docs]);
      });
  };
<div className="posts section">
    {posts.map(post => {
    return (
        <Link key={post.id} to={"/posts/" + post.id}>
         <PostCard post={post} />
        </Link>
    );
    })}
</div>

Надеюсь, это решит проблему.

...