Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
169 views
in Technique[技术] by (71.8m points)

javascript - React batches state updates from different useEffects?

In the below code snapshot, there are 5 different state updates called in useEffects; 3 in the first and 2 in the second.

I log my code and see that the screen has only rendered 3 times, so 1 initial render and 2 additional renders.

Interestingly, if I comment out / remove the entire second useEffect, I still get 3 renders, so nothing changes. This leads me to believe that state updates from different useEffects can be batched together?

I am also a little confused why I don't get 6 renders instead (1 initial render + 5 updates), because all my state update calls are in a .then Promise. What I read online is that in e.g. event handler code the updates are batched together but not in case of Promise... https://blog.logrocket.com/simplifying-state-management-in-react-apps-with-batched-updates/#:~:text=By%20default%2C%20React%20batches%20updates,time%20the%20call%20is%20made.

useEffect 1 state updates:

setChatsToDisplay(chats)
setChatsUsersInfo(chatsWithUsersInfo)
setChatsAreInitializing(false)

UseEffect 2 state updates:

setMatchInvites(data)
setMatchInvitesAreInitializing(false)

Full code where these updates are called:

useEffect(() => {
    getUserChats(userId)
    .then((getUserChatsData) => {
      if (getUserChatsData) {
                const chats = {}
                for (i = 0; i < getUserChatsData.length; i++) {
                    const matchedUserInArrayFormat = getUserChatsData[i]['users'].filter((users) => {
            return users !== userId
          })
                    const matchedUser = matchedUserInArrayFormat[0]
                    const message = getUserChatsData[i]['message'][0]['content']
                    chats[matchedUser] = message
                }
        const matchedChatUserIds = getUserChatsData.map(userChat => {
          const arrayWithMatchedChatUserId = userChat['users'].filter((users) => {
            return users !== userId
          })
          return arrayWithMatchedChatUserId[0]
        })
        getUserInfo(matchedChatUserIds, JSON.stringify({'name': 1, 'userId': 1, 'profilePictureURI' : 1}), 10)
        .then((userInfo) => {
          var chatsWithUsersInfo = userInfo.map((user, index) => (
            {'index': index, 'matchedUserId': user.userId, 'matchedUserProfilePictureURI': user.profilePictureURI, 'matchedUserName': user.name}
          ))
                    // Updating the states in this order below appears to render the screen two times with the same chatsToDisplay value, which is required to get previousChatsToDisplay to use the initially retrieved chats as base (not an empty Object). The useEffect that depends on [chatsToDisplay, chatsAreInitializing] can then effectively compare new chats
                    setChatsToDisplay(chats)
                    setChatsUsersInfo(chatsWithUsersInfo)
                    console.log('gonna set to false');
                    setChatsAreInitializing(false)
                })
      }
    })
  }, [])
    
    useEffect(() => {
        getMatchInvites(userId, 10)
        .then((getMatchInvitesData) => {
            const data = getMatchInvitesData.map((match, index) => (
                {'index': index, 'matchedUserId': match['usersInfo'][0]['userId'], 'matchType': match['matchType'], 'matchedUserRating': match['usersInfo'][0]['rating'], 'matchId': match['_id']}
            ))
            setMatchInvites(data)
            // To-do: Check my logic for this screen and how it holds with this included
            setMatchInvitesAreInitializing(false)
        })
    }, [])

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If all those setState methods are from useState calls, I would actually try to go over to using a https://reactjs.org/docs/hooks-reference.html#usereducer. Some discussion on it here: https://stackoverflow.com/a/64942458/14953263

This lets you tackle complex state in a better smoother way, avoiding all these batched updates and potential strange behaviour.

The reducer lets you update on actions, coming from redux, but with a much more lightweight API that lets you use it for certain components


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...