反应使用效果比较对象

2022-08-30 04:45:29

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

我的代码看起来像这样。

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

    return {
        data
    };
};

不幸的是,它一直在运行,因为对象没有被识别为相同。

我认为下面就是一个原因的例子。

const objA = {
   method: 'GET'
}

const objB = {
   method: 'GET'
}

console.log(objA === objB)

也许跑步有效?JSON.stringify(apiOptions)


答案 1

用作状态值apiOptions

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

const [apiOptions, setApiOptions] = useState({ a: 1 })
const { data } = useExample(apiOptions)

这样,只有在使用 时才会更改。setApiOptions

示例 #1

import { useState, useEffect } from 'react';

const useExample = (apiOptions) => {
  const [data, updateData] = useState([]);
  
  useEffect(() => {
    console.log('effect triggered')
  }, [apiOptions]);

  return {
    data
  };
}
export default function App() {
  const [apiOptions, setApiOptions] = useState({ a: 1 })
  const { data } = useExample(apiOptions);
  const [somethingElse, setSomethingElse] = useState('default state')

  return <div>
    <button onClick={() => { setApiOptions({ a: 1 }) }}>change apiOptions</button>
    <button onClick={() => { setSomethingElse('state') }}>
      change something else to force rerender
    </button>
  </div>;
}

或者

你可以写一个深度的可比性,如下所述: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,
    dependencies.map(useDeepCompareMemoize)
  )
}

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


答案 2

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

你必须使用和从Lodash。在 中,如果一个等于当前 ,则放置一个条件。如果为真,则不执行任何操作。如果错误更新数据()usePrevious()_.isEqual()useEffect()apiOptionsapiOptions

例:

const useExample = (apiOptions) => {

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

usePrevious(value)是一个自定义钩子,它创建一个 with .refuseRef()

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

const usePrevious = value => {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
};