ReactJS - 低效的 useEffect 运行了四次
ReactJS - Inefficient useEffect runs four times
我有一个 useEffect 函数,它必须等待四个值通过单独的 useEffect 中的 API 调用来改变它们的状态。本质上,任务必须同步发生。必须从 API 中提取值,并且必须在调用第二个 useEffect 之前设置这些有状态变量并使其成为当前变量。我能够在不同步执行这些任务的情况下获得适当设置的值并正确呈现我的组件,我有一个 ref 在第一次呈现(initRender)后从 true 变为 false,但是我发现代码是 hacky 和低效的,因为事实上,第二个 useEffect 仍然运行了四次。有没有更好的方法来处理这个问题?
//Hook for gathering group data on initial page load
useEffect(() => {
console.log("UseEffect 1 runs once on first render");
(async () => {
const response = await axios.get(`${server}${gPath}/data`);
const parsed = JSON.parse(response.data);
setGroup(parsed.group);
setSites(parsed.sites);
setUsers(parsed.users);
setSiteIDs(parsed.sitesID);
setUserIDs(parsed.usersID);
})();
return function cleanup() {};
}, [gPath]);
//Hook for setting sitesIN and usersIN values after all previous values are set
useEffect(() => {
console.log("This runs 4 times");
if (
!initRender &&
sites?.length &&
users?.length &&
userIDs !== undefined &&
siteIDs !== undefined
) {
console.log("This runs 1 time");
setSitesIN(getSitesInitialState());
setUsersIN(getUsersInitialState());
setLoading(false);
}
}, [sites, siteIDs, users, userIDs]);
编辑:第二个 useEffect 的 if 语句中的代码现在只运行一次,但效果仍然运行 4 次,这仍然意味着 4 次渲染。我更新了上面的代码以反映我所做的更改。
最后编辑:对于任何在未来看到这种情况并且很难集中精力更新有状态变量的人,当这些更新发生时,有多种方法来处理这个问题,如果你知道最初的像我一样检查变量的状态,您可以在第二个 useEffect 中设置依赖项数组,然后使用 if 语句检查一个或多个更改。或者,如果您不知道初始状态,但您知道在您可以使用数据之前需要更改依赖项的状态,则可以创建引用并以这种方式跟踪状态。只需按照评论中链接的帖子中的示例进行操作即可。
我撒谎了:这是最后一次编辑!有人问,为什么不能将不同的有状态变量(例如 sites 和 sitesIN)组合成一个有状态变量,以便它们同时更新?所以我做到了,因为在我的用例中这是可以接受的。所以现在我不需要第二个useEffect。高效代码现在高效!
您的网站 !== [] ... 未按您的预期运行。你需要做
sites?.length && users?.length
检查数组是否为空。这将有助于防止多次运行。
我有一个 useEffect 函数,它必须等待四个值通过单独的 useEffect 中的 API 调用来改变它们的状态。本质上,任务必须同步发生。必须从 API 中提取值,并且必须在调用第二个 useEffect 之前设置这些有状态变量并使其成为当前变量。我能够在不同步执行这些任务的情况下获得适当设置的值并正确呈现我的组件,我有一个 ref 在第一次呈现(initRender)后从 true 变为 false,但是我发现代码是 hacky 和低效的,因为事实上,第二个 useEffect 仍然运行了四次。有没有更好的方法来处理这个问题?
//Hook for gathering group data on initial page load
useEffect(() => {
console.log("UseEffect 1 runs once on first render");
(async () => {
const response = await axios.get(`${server}${gPath}/data`);
const parsed = JSON.parse(response.data);
setGroup(parsed.group);
setSites(parsed.sites);
setUsers(parsed.users);
setSiteIDs(parsed.sitesID);
setUserIDs(parsed.usersID);
})();
return function cleanup() {};
}, [gPath]);
//Hook for setting sitesIN and usersIN values after all previous values are set
useEffect(() => {
console.log("This runs 4 times");
if (
!initRender &&
sites?.length &&
users?.length &&
userIDs !== undefined &&
siteIDs !== undefined
) {
console.log("This runs 1 time");
setSitesIN(getSitesInitialState());
setUsersIN(getUsersInitialState());
setLoading(false);
}
}, [sites, siteIDs, users, userIDs]);
编辑:第二个 useEffect 的 if 语句中的代码现在只运行一次,但效果仍然运行 4 次,这仍然意味着 4 次渲染。我更新了上面的代码以反映我所做的更改。
最后编辑:对于任何在未来看到这种情况并且很难集中精力更新有状态变量的人,当这些更新发生时,有多种方法来处理这个问题,如果你知道最初的像我一样检查变量的状态,您可以在第二个 useEffect 中设置依赖项数组,然后使用 if 语句检查一个或多个更改。或者,如果您不知道初始状态,但您知道在您可以使用数据之前需要更改依赖项的状态,则可以创建引用并以这种方式跟踪状态。只需按照评论中链接的帖子中的示例进行操作即可。
我撒谎了:这是最后一次编辑!有人问,为什么不能将不同的有状态变量(例如 sites 和 sitesIN)组合成一个有状态变量,以便它们同时更新?所以我做到了,因为在我的用例中这是可以接受的。所以现在我不需要第二个useEffect。高效代码现在高效!
您的网站 !== [] ... 未按您的预期运行。你需要做
sites?.length && users?.length
检查数组是否为空。这将有助于防止多次运行。