1

I'm trying to create a Twitter clone, and I'm having troubles with my news feed. Basically it pulls tweets from my firebase database for each user followed by the current user. So say you follow Jon Abrahams and Terry Crews, for each of these 2, it'll pull the "tweets" collection, and for each tweet, it'll return the data.

I did this with useState and useContext ( since I needed Context and couldn't make it work in a class component, but also needed state ).

  const CurrentUser = useContext(CurrentUserContext);
  const [tweets, setTweets] = useState({tweets: []});

  const feedTheFeed = async (id) => {
  const followedUsers = await getFollowedUsers(id);

  if(followedUsers) {
    followedUsers.docs.forEach(async doc => {
      const followedId = doc.data();
      const unformatTweets = await getTweetsByUser(followedId.follows);

      if(unformatTweets.docs) {
        unformatTweets.docs.map(unformatTweet => {
          const tweetText = unformatTweet.data();

          setTweets({
            tweets: [...tweets, tweetText]
          })
          // console.log(tweetText);
        })
      }
    })

    // console.log(tweets);
  }

  }

  useEffect(() => {
    if(!CurrentUser) return;

    if(CurrentUser.id || CurrentUser.uid) {
      feedTheFeed(CurrentUser.id);
    }
  }, [CurrentUser]);

The problem is that there's an issue when loading the component, it says that "tweets is not iterable", but it's an array, so I don't see why it wouldn't work. Does anyone have an idea ?

Thank you !

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Mael Landrin
  • 103
  • 3
  • 12
  • 5
    It's *not* an array; the initial value is `{ tweets: [] }`, so `tweets` is an object and `tweets.tweets` is the array. – jonrsharpe Jul 05 '20 at 22:27
  • Right, no idea why I added "tweet" when setting the default value.. I changed it, and now I get only one item in the array when logging the tweets in the return() statement, I had that problem earlier when trying different things – Mael Landrin Jul 05 '20 at 22:36
  • If you log it right after `setTweets` you're still seeing the old value; it's not updated until the component re-renders and `useState` is called again. – jonrsharpe Jul 05 '20 at 22:37
  • I'm logging it in the return() statement at the end when displaying the component, there's a first item, and on the next loop the tweet replaces the previous one – Mael Landrin Jul 05 '20 at 22:40

2 Answers2

3

Seems like what you want is

const [tweets, setTweets] = useState([]);

and

setTweets([...tweets, tweetText])
Rubydesic
  • 3,386
  • 12
  • 27
  • That makes sense, thanks ! Though now I always get one item in the array when I console.log() it in the return() part of the component – Mael Landrin Jul 05 '20 at 22:34
  • 1
    upvote you, but I think better use callback: `setTweets(oldTweets => [...oldTweets , tweetText]);` – Omer Jul 05 '20 at 22:42
  • It’s late here so I’m leaving it for today, I’ll try the prevTweets thing tomorrow, I knew this for setState but didn’t know if could be used with hooks, thanks – Mael Landrin Jul 05 '20 at 22:47
  • @Omer, if I'm not mistaken, that code doesn't work because it will set 'tweets' to be a function. – Rubydesic Jul 05 '20 at 22:47
  • Take a look (https://stackoverflow.com/questions/55342406/updating-and-merging-state-object-using-react-usestate-hook) – Omer Jul 05 '20 at 23:26
0

I think what you want to do is this.....

const [tweets, setTweets] = useState([]);

setTweets(b => [...b, tweetText])

  • 1
    When adding answer to an old question (13 months ago), consider reading other's answer before posting yours. Your answer has been included [here](https://stackoverflow.com/a/62747037/6670491). – HardcoreGamer Aug 16 '21 at 03:01