反应useEffect比较对象

pet*_*gan 19 javascript reactjs react-hooks

我正在使用react useEffect挂钩并检查对象是否已更改,然后才再次运行挂钩。

我的代码如下所示。

const useExample = (apiOptions) => {
    const [data, updateData] = useState([]);
    useEffect(() => {
       const [data, updateData] = useState<any>([]);
        doSomethingCool(apiOptions).then(res => {               
           updateData(response.data);
       })
    }, [apiOptions]);

    return {
        data
    };
};
Run Code Online (Sandbox Code Playgroud)

不幸的是,由于对象未被识别为相同对象,因此它一直在运行。

我相信以下是一个示例。

const useExample = (apiOptions) => {
    const [data, updateData] = useState([]);
    useEffect(() => {
       const [data, updateData] = useState<any>([]);
        doSomethingCool(apiOptions).then(res => {               
           updateData(response.data);
       })
    }, [apiOptions]);

    return {
        data
    };
};
Run Code Online (Sandbox Code Playgroud)

也许运行的JSON.stringify(apiOptions)作品?

len*_*ndc 12

使用apiOptions的状态值

我不确定您如何使用自定义钩子,但是apiOptions通过使用来创建状态值useState应该可以正常工作。这样,您可以将其作为状态值提供给自定义钩子,如下所示:

const [apiOptions, setApiOptions] = useState({ a: 1 })
const { data } = useExample(apiOptions)
Run Code Online (Sandbox Code Playgroud)

这样,只有在使用时,它才会改变setApiOptions

例子1

const [apiOptions, setApiOptions] = useState({ a: 1 })
const { data } = useExample(apiOptions)
Run Code Online (Sandbox Code Playgroud)

或者

你可以写一个深可比useEffect的描述在这里

function deepCompareEquals(a, b){
  // TODO: implement deep comparison here
  // something like lodash
  // return _.isEqual(a, b);
}

function useDeepCompareMemoize(value) {
  const ref = useRef() 
  // it can be done by using useMemo as well
  // but useRef is rather cleaner and easier

  if (!deepCompareEquals(value, ref.current)) {
    ref.current = value
  }

  return ref.current
}

function useDeepCompareEffect(callback, dependencies) {
  useEffect(callback, useDeepCompareMemoize(dependencies))
}
Run Code Online (Sandbox Code Playgroud)

您可以像使用一样使用它useEffect

  • 感谢您的帮助,但我不想采用这种方法,因为可能有很多 API 选项。我已经通过使用`JSON.stringify` 解决了这个问题,但看起来这里描述了一种更好的方法,但我无法访问 egghead :-( /sf/ask/3752135201/使用效果第二个参数 (3认同)

kas*_*oyo 12

如果您确定无法控制,apiOptions那么只需将原生 useEffect 替换为https://github.com/kentcdodds/use-deep-compare-effect


Ste*_*ffi 10

我刚刚找到了适合我的解决方案。

你必须使用usePrevious()_.isEqual()从Lodash。在中useEffect(),如果前一个 apiOptions等于当前 条件,则放置一个条件apiOptions。如果为true,则不执行任何操作。如果为false,则updateData()

范例:

const useExample = (apiOptions) => {

     const myPreviousState = usePrevious(apiOptions);
     const [data, updateData] = useState([]);
     useEffect(() => {
        if (myPreviousState && !_.isEqual(myPreviousState, apiOptions)) {
          updateData(apiOptions);
        }
     }, [apiOptions])
}
Run Code Online (Sandbox Code Playgroud)

usePrevious(value)是创建一个自定义的钩子refuseRef()

您可以从官方的React Hook文档中找到它。

const usePrevious = value => {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
};
Run Code Online (Sandbox Code Playgroud)

  • 它是否会收到有关缺少依赖项“myPreviousState”的警告? (3认同)

adl*_*adl 10

如果输入足够浅,您认为深度相等仍然很快,请考虑使用JSON.stringify

const useExample = (apiOptions) => {
    const [data, updateData] = useState([]);
    const apiOptionsJsonString = JSON.stringify(apiOptions);

    useEffect(() => {
       const apiOptionsObject = JSON.parse(apiOptionsJsonString);
       doSomethingCool(apiOptionsObject).then(response => {               
           updateData(response.data);
       })
    }, [apiOptionsJsonString]);

    return {
        data
    };
};
Run Code Online (Sandbox Code Playgroud)

请注意,它不会比较功能。

  • 当“apiOptions”是一个不太复杂的数据对象时,这似乎是一个很好且简单的解决方案。但我想知道:是否有必要在 useEffect() 中执行 `JSON.parse(apiOptionsJsonString)` ?你不能简单地使用父作用域中的“apiOptions”吗? (3认同)
  • @marcvangend,如果您使用父作用域中的“apiOptions”,则必须将其添加为 useEffect 的依赖项,这将带来问题。 (3认同)