我有一个 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 处理监听器?
答案 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