【发布时间】:2021-09-12 22:00:35
【问题描述】:
简介
我当前的用例需要将最新的状态更新存储在缓存中。由于状态更新是异步的,并且可能有很多组件并行更新同一个组件,因此将它们存储在 useState 或 useReducer 纯函数的主体中可能是一个不错的选择。
但是……副作用来了,挫折感开始了。我试图等待调度,创建自定义钩子“useReducerWithCallback”和其他东西,但我没有看到我的问题的正确解决方案。
问题
我有一个模块 usersCache.js,它为我提供了修改缓存的必要方法:
const cache = {};
export const insert = (id, data) => ...
export const get = (id) => ...
// and more stuff
我正在尝试在进行状态更新时更新此缓存。例如:
const currentUser = useContext(CurrentUserContext);
...
// Note: setData is just the state setter useState hook
currentUser.setData((prevData) => {
const newTotalFollowing = prevData.totalFollowing + 1;
usersCache.update(currentUser.data.id, { newTotalFollowing }); <---- SIDE EFFECT
return { ...prevData, totalFollowing: newTotalFollowing };
});
在我的 otherUsers reducer
中也有同样的东西import { usersCache } from "../../services/firebase/api/users"
export default (otherUsers, action) => {
switch (action.type) {
case "follow-user": {
const { userId, isFollowing } = action;
const prevUserData = otherUsers.get(userId);
const newTotalFollowers = prevUserData.totalFollowers + (isFollowing ? 1 : -1);
usersCache.update(userId, { totalFollowers: newTotalFollowers }); // merge update
return new Map([
...otherUsers,
[
userId,
{
...prevUserData,
totalFollowers: newTotalFollowers
]
]
);
}
...
}
}
在纯函数中,我们不应该执行副作用......有没有其他方法来处理这个?
注意:我没有使用 Redux
【问题讨论】:
-
解决方案
useEffect() -
@RandyCasburn 但是由于状态更新是异步的...例如,如果有多个组件尝试并行更新相同的状态,那么 useEffect 回调不会以混乱的方式执行?
-
在您给出的示例中,您甚至没有使用 usersCache。由于该用户状态已经在该 React 上下文中,如果您只是删除 usersCache 模块,究竟会出现什么问题?
-
如果您还记得您的 ACID 理论,那么数据一致性是事件源系统的权衡。一个组件可能会在某些上下文状态上发出删除,然后另一个组件可能会使用过期状态作为参考发出更新。这是支持离线系统的常见问题,但它实际上是您的应用程序中的问题吗?
-
感谢您提供的额外信息,将您的问题包含在其中会非常有帮助!你走在正确的轨道上,它永远不会漂亮(或纯粹)。如果你想避免将你的状态非规范化到缓存中,那么你可以制作一个像 useFetchIfNeeded 这样的钩子,它接受一个 api 函数和一个在上下文中查找状态的键。或者继续做你正在做的事情,但是做一个像 useStateWithAPICache 这样的钩子,它也接受一个你添加到缓存对象的键。
标签: javascript reactjs react-native react-redux react-hooks