在useEffect第二参数中使用对象,而不必将其字符串化为JSON

在JS中,两个对象不相等。

const a = {}, b = {};

console.log(a === b);

所以我不能使用useEffect(React hooks)中的对象作为第二个参数,因为它始终被视为false(因此它将重新呈现):

function MyComponent() {

// ...

useEffect(() => {

// do something

}, [myObject]) // <- this is the object that can change.

}

这样做(上面的代码), 每次 重新渲染组件时都会产生运行效果,因为 每次 都认为对象不相等。

我可以通过将对象作为JSON字符串化值传递来“破解”,但是IMO有点脏:

function MyComponent() {

// ...

useEffect(() => {

// do something

}, [JSON.stringify(myObject)]) // <- yuck

有没有更好的方法可以做到这一点并避免不必要的效果调用?

注意:对象具有嵌套属性。 效果必须在此对象内的所有更改上运行。

回答:

您可以创建一个自定义钩子,该钩子跟踪a中的先前依赖项数组,ref并与对象(例如Lodash)进行比较,isEqual并且仅在它们不相等时才运行提供的函数。

const { useState, useEffect, useRef } = React;

const { isEqual } = _;

function useDeepEffect(fn, deps) {

const isFirst = useRef(true);

const prevDeps = useRef(deps);

useEffect(() => {

const isSame = prevDeps.current.every((obj, index) =>

isEqual(obj, deps[index])

);

if (isFirst.current || !isSame) {

fn();

}

isFirst.current = false;

prevDeps.current = deps;

}, deps);

}

function App() {

const [state, setState] = useState({ foo: "foo" });

useEffect(() => {

setTimeout(() => setState({ foo: "foo" }), 1000);

setTimeout(() => setState({ foo: "bar" }), 2000);

}, []);

useDeepEffect(() => {

console.log("State changed!");

}, [state]);

return <div>{JSON.stringify(state)}</div>;

}

ReactDOM.render(<App />, document.getElementById("root"));

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>

<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

以上是 在useEffect第二参数中使用对象,而不必将其字符串化为JSON 的全部内容, 来源链接: utcz.com/qa/430067.html

回到顶部