переменная снаружи foreach равна нулю, но имеет значение внутри - PullRequest
1 голос
/ 21 апреля 2020

У меня есть эта reactjs функция для получения данных из базы данных. Проблема в массиве postsArray. У него внутри foreach есть объекты, а снаружи - ноль.

Я добавляю postsArray глобально.

Есть идеи, почему возвращение равно нулю?

postsRef.on('value', function(snapshot) {
    setPosts(prevPosts => {

        snapshot.forEach((subChild) => {
            var value = subChild.val();
            value = value.postID;

            var post = firebase.database().ref('/posts/' + value);

            post.on('value', function(snapshot2) {

                postsArray = snapshot2.val();
                console.log(postsArray); // HAS THE VALUE

            });

            console.log(postsArray); // NO VALUE HERE.


        });

return [...prevPosts, ...Object.keys(postsArray).reverse().map(key => ({
    key: key, ...postsArray[key] 
}))];

Ответы [ 2 ]

1 голос
/ 21 апреля 2020

post.on является асинхронной c функцией, поэтому значение за пределами forEach l oop не определено для postArray

Решение здесь состоит в том, чтобы установить состояние внутри post.on. Это, однако, приведет к множественному setState, а также продолжит добавлять состояние данных postArray.

postsRef.on('value', function(snapshot) {
  snapshot.forEach((subChild) => {
      var value = subChild.val();
      value = value.postID;
      var post = firebase.database().ref('/posts/' + value);
      post.on('value', function(snapshot2) {
          postsArray = snapshot2.val();
            setPosts(prevPosts => {
              return [...prevPosts, ...Object.keys(postsArray).reverse().map(key => ({
                key: key, ...postsArray[key] 
            }))];
            })
      });
  })
})

Лучшим решением здесь является преобразование синтаксиса обратного вызова для использования обещания. Я не уверен, что firebase.database предоставляет формат обещания, поэтому я просто покажу вам традиционный способ использования Promise.all и нового Promise

postsRef.on('value', async function(snapshot) {
  const promises = []
  snapshot.forEach((subChild) => {
      var value = subChild.val();
      value = value.postID;
      var post = firebase.database().ref('/posts/' + value);
      promises.push(new Promise((res, rej) => {
         post.on('value', function(snapshot2) {
           res(snapshot2.val())
        });
     }));
  })
  const postArray = await Promise.all(promises);
  setPosts(prevPosts => {
      return [
          ...prevPosts,  
          ...Object.keys(postsArray).reverse().map(key => ({
                key: key, ...postsArray[key] 
            }))
      ];
   })
})
1 голос
/ 21 апреля 2020

post.on() - асинхронный прослушиватель событий, ваш текущий код синхронен. Если вы опубликуете больше своего кода, я могу помочь вам реструктурировать его.

То, что происходит:

var post = firebase.database().ref('/posts/' + value);
var postFunction = function(snapshot2) {
   postsArray = snapshot2.val();
   console.log(postsArray); // HAS THE VALUE
};
// set the post on function. This isn't calling the function yet.
post.on('value', postFunction);
// No value here because the post function has not run yet.
console.log(postsArray); // NO VALUE HERE.
// the postFunction post.on is called so now you will get the console.

Я бы изменил его так:

const addNewPostsToPrevious = (prevPosts) => (newPosts) => {
  return [
    ...prevPosts,
    ...Object.keys(newPosts)
      .reverse()
      .map((key) => ({
        key,
        ...newPosts[key],
      })),
  ];
};
postsRef.on('value', (snapshot) => {
  setPosts((prevPosts) => {
    snapshot.forEach((subChild) => {
      const post = firebase.database().ref(`/posts/${subChild.val().postID}`);
      post.on('value', (snapshot2) => {
        addNewPostsToPrevious(prevPosts)(snapshot2.val());
      });
    });
  });
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...