嵌套对象的无限循环
Infinite loop with nested object
如果我使用 { data: {}} 为什么它会循环,而 { data: {} 一切正常?
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [test, setTest] = useState(true);
const role = useRole({ data: {} }); // with object { data: 1 } all fine
useEffect(() => {
setTest(false);
}, []);
return 1;
}
export function useRole({ data }) {
const [role, roleSet] = useState(false);
useEffect(() => {
console.log("looping");
roleSet({});
}, [data]);
return role;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
我认为这与 javascript 的工作方式有关。
在 React 中,默认情况下每次渲染后 useEffect
运行 秒。自定义该行为的一种方法是提供一个列表作为第二个参数。
这样,React 将在渲染后根据上一次渲染提供的值进行检查,并仅在值发生变化时调用效果。
这就是问题所在,您可以通过以下示例进行验证:
if(1 === 1) {
console.log("1 === 1");
}
if({} === {}) {
console.log("{} === {}");
}
如果你 运行 这你可能会注意到这里的输出只有 1 === 1。那是因为 javascript 没有将两个空对象视为相等。
由于您提供 { data: {} }
并在 useRole
中解压数据值,因此您的列表中有一个空对象。
希望对您有所帮助。
我觉得@TvG说的很到位。对象比较是通过引用完成的。
当您按照您在代码中所做的方式创建对象时,每次都会创建新的引用对象。
const role = useRole({ data: {} });
即使你这样做:
let defaultRole = { data: {} }
const role = useRole(defaultRole);
每次都会创建新对象。 defaultRole 的值将在每次渲染时重新计算。
这里可以做的是,React 为我们提供了 useRef 方法,除非明确更改,否则不会在重新渲染时更改。这里是link供您阅读:
useRef docs
你可以这样做:
const { useEffect, useState, useRef } = React
function App() {
const [test, setTest] = useState(true);
console.log("running this")
let baseObj = {
data: {}
}
const roleDefaultValueRef = useRef(baseObj)
const role = useRole(roleDefaultValueRef.current);
useEffect(() => {
setTest(false);
}, []);
return 1
}
function useRole({ data }) {
const [role, roleSet] = useState(false);
useEffect(() => {
console.log("looping");
roleSet({});
debugger
}, [data]);
return role;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id="root"></div>
跟进问题为什么像 data = {} 这样的对象在这种情况下会起作用。
所以你的 useRole 有一个依赖于数据的效果。假设您将 useRole 称为 useRole({})
现在在您的 useRole 中,您正在从这个传递的对象中传播数据值 {}
所以这一行
export function useRole({ data }) {
// data will be evaluated as undefined and undefined will remain same on //consecutive rerenders and hence the effect will not run
}
这就是当您将空白对象传递给 useRole 时 运行 的原因。
希望这对您有所帮助。
FOR understanding try to print the value of data in useRole,你一定会明白的:)
1 === 1 //true
undefined === undefined //true
{} === {} // false
如果我使用 { data: {}} 为什么它会循环,而 { data: {} 一切正常?
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [test, setTest] = useState(true);
const role = useRole({ data: {} }); // with object { data: 1 } all fine
useEffect(() => {
setTest(false);
}, []);
return 1;
}
export function useRole({ data }) {
const [role, roleSet] = useState(false);
useEffect(() => {
console.log("looping");
roleSet({});
}, [data]);
return role;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
我认为这与 javascript 的工作方式有关。
在 React 中,默认情况下每次渲染后 useEffect
运行 秒。自定义该行为的一种方法是提供一个列表作为第二个参数。
这样,React 将在渲染后根据上一次渲染提供的值进行检查,并仅在值发生变化时调用效果。
这就是问题所在,您可以通过以下示例进行验证:
if(1 === 1) {
console.log("1 === 1");
}
if({} === {}) {
console.log("{} === {}");
}
如果你 运行 这你可能会注意到这里的输出只有 1 === 1。那是因为 javascript 没有将两个空对象视为相等。
由于您提供 { data: {} }
并在 useRole
中解压数据值,因此您的列表中有一个空对象。
希望对您有所帮助。
我觉得@TvG说的很到位。对象比较是通过引用完成的。 当您按照您在代码中所做的方式创建对象时,每次都会创建新的引用对象。
const role = useRole({ data: {} });
即使你这样做:
let defaultRole = { data: {} }
const role = useRole(defaultRole);
每次都会创建新对象。 defaultRole 的值将在每次渲染时重新计算。
这里可以做的是,React 为我们提供了 useRef 方法,除非明确更改,否则不会在重新渲染时更改。这里是link供您阅读:
useRef docs 你可以这样做:
const { useEffect, useState, useRef } = React
function App() {
const [test, setTest] = useState(true);
console.log("running this")
let baseObj = {
data: {}
}
const roleDefaultValueRef = useRef(baseObj)
const role = useRole(roleDefaultValueRef.current);
useEffect(() => {
setTest(false);
}, []);
return 1
}
function useRole({ data }) {
const [role, roleSet] = useState(false);
useEffect(() => {
console.log("looping");
roleSet({});
debugger
}, [data]);
return role;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id="root"></div>
现在在您的 useRole 中,您正在从这个传递的对象中传播数据值 {} 所以这一行
export function useRole({ data }) {
// data will be evaluated as undefined and undefined will remain same on //consecutive rerenders and hence the effect will not run
}
这就是当您将空白对象传递给 useRole 时 运行 的原因。
希望这对您有所帮助。 FOR understanding try to print the value of data in useRole,你一定会明白的:)
1 === 1 //true
undefined === undefined //true
{} === {} // false