使用带有 React useEffect 钩子的监听器

时间:2021-02-25 07:03:03

标签: reactjs react-native react-hooks

我有一个 useEffect 钩子来处理我的应用程序中的在线用户

const [users, setUsers] = useState({} as Users);

useEffect(() => {
    const handleOnlineStatus = (onlineStatus: Array<OnlineStatus>) => {
    const usersCopy = {...users};
    if (onlineStatus.length === 0) {
        return;
    }


    onlineStatus.forEach((status: OnlineStatus) => {
        const uid = status.userId;

        if (!uid) {
        return;
        }

        if (uid in usersCopy) {
        const lastStatus = usersCopy[uid].status;
        if (lastStatus !== usersCopy) {
            usersCopy[uid].status = status.value;

            setUsers({...usersCopy});
        }
        }
    });
    };
    subscribeToIsOnline((onlineStatus: Array<OnlineStatus>) => {
        handleOnlineStatus(onlineStatus);
    });
});

public handleOnlineStatus(callback: (users: Array<OnlineStatus>) => void) {
    this.logDebug('subscribeToOnlineStatusIndication');

    try {
      return ChatClient.addListener('OnlineStatusIndication', (users: Array<OnlineStatus>) => callback(users));
    } catch (e) {
      this.logError(e);
    }
}

但是使用此代码,每次用户重新上线时都会重新创建侦听器。 所以我更新了这样的代码:

useEffect(() => {
    // ... same code
}, []); // <--

但是使用这个新代码,setUsers 永远不会重新渲染视图。

如何使用 react hooks 处理监听器?

1 个答案:

答案 0 :(得分:2)

我认为您是在正确的轨道上,但您已将初始 users 状态对象 ({}) 包含在回调中。换句话说,它是一个陈旧的外壳,因此您总是从初始渲染中复制 users 状态。

您也在使用 usersCopy[uid].status = status.value; 改变状态。

使用功能状态更新来访问您可以从中更新的先前状态。

const [users, setUsers] = useState({} as Users);

useEffect(() => {
  const handleOnlineStatus = (onlineStatus: Array<OnlineStatus>) => {
    if (!onlineStatus.length) {
      return;
    }

    onlineStatus.forEach((status: OnlineStatus) => {
      const uid = status.userId;

      if (!uid) {
        return;
      }

      setUsers(users => {
        if (uid in users) {
          const lastStatus = users[uid].status;
          if (lastStatus !== users) {
            return {
              ...users, // <-- shallow copy into new state object
              [uid]: {
                ...users[uid], // <-- shallow copy old user object
                status: status.value, // <-- update property
              }
            };
          }
        }
        return users; // <-- old state
      });
    });
  };

  subscribeToIsOnline((onlineStatus: Array<OnlineStatus>) => {
    handleOnlineStatus(onlineStatus);
  });
}, []); // <-- empty dependency array to run effect once