【问题标题】:React - Running side effects inside pure functionsReact - 在纯函数中运行副作用
【发布时间】: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


【解决方案1】:

您可以使用存储库模式和反应挂钩检查此full working example,以通过状态调度简化异步操作。我知道您没有使用 redux,但您可以使用 useReducer 挂钩调整此示例,将其连接到您的 React Context 存储。

【讨论】:

    猜你喜欢
    • 2020-06-25
    • 2013-08-12
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2010-12-27
    相关资源
    最近更新 更多