比较对象的效果

我正在使用反应 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)有用?

140816 次浏览

使用 apiOptions作为状态值

我不确定您是如何使用自定义钩子的,但使用 useState使 apiOptions成为一个状态值应该就可以了。通过这种方式,您可以将其作为状态值提供给自定义钩子,如下所示:

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一样使用它。

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

你必须使用来自 Lodash 的 ABc0和 ABc1。 在 useEffect()中,如果 上一页apiOptions等于 目前apiOptions,那么可以设置一个条件。如果是真的,什么都别做。如果错误 UpdateData ()

例如:

const useExample = (apiOptions) => {


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

usePrevious(value)是一个定制的钩子,它用 useRef()创建一个 ref

你可以在 官方反应钩文件上找到它。

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

如果您确实无法控制 apiOptions,那么只需用 https://github.com/kentcdodds/use-deep-compare-effect替换原生 useEffect 即可。

如果输入足够浅,以至于您认为深度相等仍然很快,可以考虑使用 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
};
};

注意,它不会比较函数。

你可以使用 useDeepCompareeffect,useCustomCompareeffect 或者编写你自己的钩子。

Https://github.com/kentcdodds/use-deep-compare-effect Https://github.com/sanjagh/use-custom-compare-effect

某个案子中真的很简单!

const objA = {
method: 'GET'
}


const objB = {
method: 'GET'
}


console.log(objA === objB) // false

为什么 对象不等于 反对?因为 JS 只是比较他们的地址,对吗?它们是两个不同的对象。我们都知道!

和反作用钩子一样!

我们都知道,objecA.method = = objecB.method 对吧? 因为它们是字面的。

答案出来了:

React.useEffect(() => {
// do your facy work
}, [obj.method])

还有一个选择,如果你有能力修改 doSomethingCool:

如果确切地知道您需要哪些非 Object属性,您可以将依赖项列表限制为 useEffect将用 ===正确解释的属性,例如:

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


return {
data
};
};