javascript - React Hooks - useDidUpdateEffect 深度比较

标签 javascript reactjs react-native react-hooks

我有以下 useDidUpdateEffect Hook

import { useRef, useEffect } from "react";

export default function useDidUpdateEffect(effect, deps) {
  const didMount = useRef(false);

  useEffect(() => {
    if (didMount.current) {
      effect();
    } else {
      didMount.current = true;
    }
  }, deps);
}

我目前使用它如下:

useDidUpdateEffect(() => { ... }, [JSON.stringify(complexNestedObject)]);

问题是,由于我的 dep 复杂而深入,有时会在没有必要的情况下执行回调。

我有一个useEffect的解决方案,就是useDeepEffect:

import { useRef, useEffect } from "react";
import { isEqual } from "lodash";

export default function useDeepEffect(effect, deps = undefined) {
  const isFirst = useRef(true);
  const prevDeps = useRef(deps);

  useEffect(() => {
    const isSame = prevDeps.current.every((obj, index) =>
      isEqual(obj, deps[index])
    );

    if (isFirst.current || !isSame) {
      effect();
    }

    isFirst.current = false;
    prevDeps.current = deps;
  }, deps);
}

但我想不出有什么可以与 useDidUpdateEffect 进行深入比较,而无需创建另一个 Hook 。

有什么想法吗?

====================

更新:

由于这种情况,我处于这种情况。也许这可以做得更简单,但老实说,我尽力了(我不是 super 专业)

  1. I have a folder "api" with different modules which contains different functions to connect to my server (I am not using hooks for this part)
   services/
       firebase/
           api/
              users/
                 helpers/
                 cache/
                    usersCache.js
                 index.js
                 ...

如您所见,我有一个模块“usersCache.js”(内存模式),它将避免一些 RTT 并降低成本。为了避免 RAM 出现问题,我在那里实现了缓存算法“LRU”。

  1. In my app I am not using REDUX (maybe the worst idea I have taken, but too late to adapt it, 90% of the work is done. Will try to learn this tech and adopt it in production, with a long refactoring).

为了管理复杂的状态,我使用了 React Context + useReducer,这在某种程度上简化了我的生活,因为它有点类似于 Redux。

就我而言,对于用户,我有 2 个上下文:

  1. 当前用户上下文
  2. 其他用户上下文

它们都包含获取用户的敏感和非敏感数据。这里你可能会想:为什么要有usersCache?如果两个上下文都可以用作内存缓存?

答案(至少我是这么认为的)是:

  1. 无法在 React 组件或 Hook 之外使用上下文。不可能在我的 api 模块中执行此操作以返回缓存数据并避免发出服务器请求。

  2. 我将敏感数据保存在依赖于当前用户 session 的上下文中(例如 isFollowed)。因此,当用户注销时,上下文将被卸载( protected 路由)。另一方面,我的 usersCache 模块仍然存在,没有敏感数据。

这是我的 CurrentUserContext 的示例(为了简单起见,我在这里没有使用 reducer,但在我的 OtherUsersContext 中,因为状态管理很复杂,所以我使用了):

import React, { createContext } from "react";

import useDidUpdateEffect from "../../hooks/useDidUpdateEffect";
import useStateWithCallback from "../../hooks/useStateWithCallback";
import { usersCache } from "../../services/firebase/api/users";

const CurrentUserContext = createContext(null);

export default CurrentUserContext;

export function CurrentUserProvider({ children }) {
  const [data, setData] = useStateWithCallback(undefined);

  const updateData = (data, merge = true, callback = undefined) => {
    if (merge) {
      setData((prevData) => ({ ...prevData, ...data }), callback);
    } else {
      setData(data, callback);
    }
  };

  useDidUpdateEffect(() => {
    console.log(JSON.stringify(data, null, 2));
    /*
      As the current user data is not sensitive, we can
      synchronize the users cache here.
    */
    usersCache.updateCachedUser(data.id, data);
  }, [JSON.stringify(data)]); // TODO - Avoid unnecessary executions -> deepCompare ?

  return (
    <CurrentUserContext.Provider
      value={{
        data,
        setData,
        updateData,
      }}
    >
      {children}
    </CurrentUserContext.Provider>
  );
}

为避免运行多个 useDidUpdateEffects,我将用户数据字符串化。但是,由于它很复杂且嵌套:

 userData = {
     avatar: {
         uri,
         thumbnailUri, 
     },
     ...
 }

当数据没有变化时执行效果,因为收到相同的数据是乱序的:

userData = {
     avatar: {
         thumbnailUri,
         uri, 
     },
     ...
 }

顶级字段也没有乱序。

最佳答案

我认为(我可能是错的)如果你使用这个效果,整个问题就会消失:

useEffect(() => {
  if(!data) return;

  // do some stuff 
},[data]);

关于javascript - React Hooks - useDidUpdateEffect 深度比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69200973/

相关文章:

javascript - 获取 net::ERR_UNKNOWN_URL_SCHEME 错误

javascript - 形成 html 谷歌脚本

javascript - 在 blueimg 中上传文件时 $_FILES 返回空结果

css - preserve-3d 不适用于子元素

javascript - 像 BBC iPlayer 一样在 iPad 上自动播放 HTML5 视频?

java - WebSocket 握手错误 : Unexpected response code: 302

android - 在React Native项目运行期间停止下载Gradle

javascript - HOC 和标准组件之间的主要区别是什么?我什么时候应该正确使用它们?

javascript - 使用参数处理事件处理函数的更好方法是什么?

react-native - 如何删除标题中的后退按钮 react 原生