gpt4 book ai didi

javascript - 从子对象设置父状态(对象)会导致不断重新渲染

转载 作者:行者123 更新时间:2023-11-30 13:45:22 26 4
gpt4 key购买 nike

我有一个父组件,里面有几个子组件。我希望能够根据 child 的状态设置 parent 的状态。

例如,假设一个父组件有 3 个子组件,它们都从服务器获取状态。然后,他们设置 parent 的状态,以便 parent 可以查看是所有 child 都有问题,还是只有几个 child 有问题。

家长:

const Parent = () => {
const [hasIssues, setHasIssues] = useState({
"child-item-1": false,
"child-item-2": false,
"child-item-3": false
});

const issuesHandler = (childName, childStatus) => {
setHasIssues({ ...hasIssues, [childName]: childStatus });
};

return (
<div>
<pre>{JSON.stringify(hasIssues, null, 2)}</pre>
<div>
<ChildItemOne issuesHandler={issuesHandler} />
<ChildItemTwo issuesHandler={issuesHandler} />
<ChildItemThree issuesHandler={issuesHandler} />
</div>
</div>
);
};

一个 child 的例子:

const ChildItemOne = ({ issuesHandler }) => {
// Imagine this is actually retrieved from a server
const hasIssues = Math.random() <= 0.75;

issuesHandler("child-item-1", hasIssues);

return <div>{`child-item-1: ${hasIssues}`}</div>;
};

当然这个例子会超过最大更新深度。我已经尝试通过使用以下示例来防止这种情况:

useEffect(() => {
issuesHandler("child-item-1", hasIssues);
}, [hasIssues, issuesHandler]);

但这仍然没有预期的结果,因为状态仍在不断更新,但没有超过最大更新深度:Codesandbox example .

我也尝试过使用 useCallback,但没有做任何事情。将 useEffect 的依赖项更改为空数组(无论如何 ESLint 不允许我在本地执行此操作),也没有用:

enter image description here

从子组件设置父级状态而不导致不断重新渲染的最佳方法是什么?

最佳答案

移动const hasIssues = Math.random() <= 0.75;进入useEffect()打回来。这将防止重新渲染循环,因为该值只会生成一次。

这也将更好地模拟对服务器的调用,因为它只会在组件安装时发生一次。

const ChildItemOne = ({ issuesHandler, hasIssues }) => {      
useEffect(() => {
// Imagine this is actually retrieved from a server
issuesHandler("child-item-1", Math.random() <= 0.75);
}, [issuesHandler]);

return <div>{`child-item-1: ${hasIssues}`}</div>;
};

parent 也应该通过hasIssues回到 child 包装issuesHandleruseCallback() ,并使用 setHasIssues() 中的更新程序回调.这将防止 issuesHandler在每个渲染器上重新创建,这反过来会导致 children 的 useEffect()被调用,等等......

const Parent = () => {
const [hasIssues, setHasIssues] = useState({
"child-item-1": false,
"child-item-2": false,
"child-item-3": false
});

const issuesHandler = useCallback((childName, childStatus) => {
setHasIssues(state => ({ ...state, [childName]: childStatus }))
}, [setHasIssues]);

return (
<div>
<pre>{JSON.stringify(hasIssues, null, 2)}</pre>
<div>
<ChildItemOne issuesHandler={issuesHandler} hasIssues={hasIssues['child-item-1']} />
<ChildItemTwo issuesHandler={issuesHandler} hasIssues={hasIssues['child-item-2']} />
<ChildItemThree issuesHandler={issuesHandler} hasIssues={hasIssues['child-item-3']} />
</div>
</div>
);
};

实例:

const { useState, useCallback, useEffect } = React;

const ChildItemOne = ({ issuesHandler, hasIssues }) => {
useEffect(() => {
// Imagine this is actually retrieved from a server
issuesHandler("child-item-1", Math.random() <= 0.75);
}, [issuesHandler]);

return <div>{`child-item-1: ${hasIssues}`}</div>;
};

const Parent = () => {
const [hasIssues, setHasIssues] = useState({
"child-item-1": false,
"child-item-2": false,
"child-item-3": false
});

const issuesHandler = useCallback((childName, childStatus) => {
setHasIssues(state => ({ ...state, [childName]: childStatus }))
}, [setHasIssues]);

return (
<div>
<pre>{JSON.stringify(hasIssues, null, 2)}</pre>
<div>
<ChildItemOne issuesHandler={issuesHandler} hasIssues={hasIssues['child-item-1']} />
</div>
</div>
);
};

ReactDOM.render(
<Parent />,
root
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

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

关于javascript - 从子对象设置父状态(对象)会导致不断重新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59447628/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com