【问题标题】:React batches state updates from different useEffects?响应来自不同 useEffects 的批量状态更新?
【发布时间】:2021-04-12 09:02:30
【问题描述】:

在下面的代码快照中,在 useEffects 中调用了 5 种不同的状态更新;第一个3个,第二个2个。

我记录了我的代码,发现屏幕只渲染了 3 次,因此 1 次初始渲染和 2 次额外渲染。

有趣的是,如果我注释掉/删除整个第二个 useEffect,我仍然会得到 3 个渲染,所以没有任何变化。这让我相信来自不同 useEffects 的状态更新可以一起批处理?

我也有点困惑,为什么我没有得到 6 个渲染(1 个初始渲染 + 5 个更新),因为我所有的状态更新调用都在 .then Promise 中。我在网上看到的是,例如事件处理程序代码将更新批处理在一起,但在 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 状态更新:

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

UseEffect 2 状态更新:

setMatchInvites(data)
setMatchInvitesAreInitializing(false)

调用这些更新的完整代码:

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)
        })
    }, [])

【问题讨论】:

  • 以后请确保您在问题中添加语言标签(我为您添加了 JS),或者将您的代码示例放在带有 lang-javascript 注释(或任何语言)的三重反引号中代码写在)。否则问题不会得到语法高亮。
  • 如果新状态与当前状态相同,则不会重新渲染。

标签: javascript react-native state hook use-effect


【解决方案1】:

如果所有这些 setState 方法都来自 useState 调用,我实际上会尝试使用 https://reactjs.org/docs/hooks-reference.html#usereducer。这里有一些讨论:https://stackoverflow.com/a/64942458/14953263

这可以让您以更流畅的方式处理复杂的状态,避免所有这些批量更新和潜在的奇怪行为。

reducer 可让您更新来自 redux 的操作,但具有更轻量级的 API,可让您将其用于某些组件

【讨论】:

    【解决方案2】:

    状态更新通常是asynchronous and are batched together,我认为它们是否具有单独的副作用并不重要。

    【讨论】:

      猜你喜欢
      • 2021-09-24
      • 2021-03-21
      • 2018-10-14
      • 2023-03-16
      • 2019-01-07
      • 2022-01-20
      • 1970-01-01
      • 2020-08-07
      • 2021-01-20
      相关资源
      最近更新 更多