React Hooks:跳过多个连续的 setState 调用的重新渲染



>假设我有以下代码:(太冗长了(

function usePolicyFormRequirements(policy) {
const [addresses, setAddresses] = React.useState([]);
const [pools, setPools] = React.useState([]);
const [schedules, setSchedules] = React.useState([]);
const [services, setServices] = React.useState([]);
const [tunnels, setTunnels] = React.useState([]);
const [zones, setZones] = React.useState([]);
const [groups, setGroups] = React.useState([]);
const [advancedServices, setAdvancedServices] = React.useState([]);
const [profiles, setProfiles] = React.useState([]);
React.useEffect(() => {
policiesService
.getPolicyFormRequirements(policy)
.then(
({
addresses,
pools,
schedules,
services,
tunnels,
zones,
groups,
advancedServices,
profiles,
}) => {
setAddresses(addresses);
setPools(pools);
setSchedules(schedules);
setServices(services);
setTunnels(tunnels);
setZones(zones);
setGroups(groups);
setAdvancedServices(advancedServices);
setProfiles(profiles);
}
);
}, [policy]);
return {
addresses,
pools,
schedules,
services,
tunnels,
zones,
groups,
advancedServices,
profiles,
};
}

当我在函数组件中使用此自定义 Hook 时,getPolicyFormRequirements解析后,我的函数组件会重新呈现9次(我调用setState的所有实体的计数(

我知道这个特定用例的解决方案是将它们聚合到一个状态中并调用setState一次,但我记得(如果我错了,请纠正我(在事件处理程序上(例如onClick( 如果调用多个连续的setState,则在事件处理程序完成执行后仅发生一次重新呈现。

我有什么办法可以告诉React,或者React会知道自己,在这setState之后,另一个setState即将到来,所以跳过重新渲染,直到你找到一秒钟呼吸。

我不是在寻找性能优化技巧,我想知道上述(粗体(问题的答案!

还是你觉得我想错了?

谢谢!

--------------


更新我如何检查我的组件渲染了 9 次?

export default function PolicyForm({ onSubmit, policy }) {
const [formState, setFormState, formIsValid] = usePgForm();
const {
addresses,
pools,
schedules,
services,
tunnels,
zones,
groups,
advancedServices,
profiles,
actions,
rejects,
differentiatedServices,
packetTypes,
} = usePolicyFormRequirements(policy);
console.log(' --- re-rendering'); // count of this
return <></>;
}

我想我会在这里发布这个答案,因为它还没有被提及。

有一种方法可以强制批处理状态更新。 有关说明,请参阅本文。 下面是一个功能齐全的组件,无论 setValues 函数是否异步,它只呈现一次。

import React, { useState, useEffect} from 'react'
import {unstable_batchedUpdates} from 'react-dom'
export default function SingleRender() {
const [A, setA] = useState(0)
const [B, setB] = useState(0)
const [C, setC] = useState(0)
const setValues = () => {
unstable_batchedUpdates(() => {
setA(5)
setB(6)
setC(7)
})
}
useEffect(() => {
setValues()
}, [])
return (
<div>
<h2>{A}</h2>
<h2>{B}</h2>
<h2>{C}</h2>
</div>
)
}

虽然"不稳定"这个名字可能令人担忧,但 React 团队之前建议在适当的情况下使用此 API,我发现在不阻塞代码的情况下减少渲染数量非常有用。

如果异步触发状态更改,React不会批处理多个状态更新。例如,在您的情况下,由于您在解析 policiesService.getPolicyFormRequirements(policy( 后调用 setState,因此 react 不会对其进行批处理。

相反,如果只是以下方式,React 将批处理 setState 调用,在这种情况下,只有 1 次重新渲染。

React.useEffect(() => {
setAddresses(addresses);
setPools(pools);
setSchedules(schedules);
setServices(services);
setTunnels(tunnels);
setZones(zones);
setGroups(groups);
setAdvancedServices(advancedServices);
setProfiles(profiles);
}, [])

我在网上找到了下面的代码沙箱示例,它演示了上述两种行为。

https://codesandbox.io/s/402pn5l989

如果您查看控制台,当您点击"带有承诺"按钮时,它将首先显示 aa 和 b b,然后显示 aa 和 b bb。

在这种情况下,它不会立即渲染 aa - bb,每个状态更改都会触发一个新的渲染,没有批处理。

但是,当您单击"无承诺"按钮时,控制台将立即显示 aa 和 b bb。所以在这种情况下,React 会批量处理状态更改,并为两者一起进行一次渲染。

您可以将所有状态合并为一个

function usePolicyFormRequirements(policy) {
const [values, setValues] = useState({
addresses: [],
pools: [],
schedules: [],
services: [],
tunnels: [],
zones: [],
groups: [],
advancedServices: [],
profiles: [],
});

React.useEffect(() => {
policiesService
.getPolicyFormRequirements(policy)
.then(newValues) => setValues({ ...newValues }));
}, [policy]);
return values;
}

顺便说一下,我刚刚发现 React 18 添加了开箱即用的自动更新批处理。阅读更多:https://github.com/reactwg/react-18/discussions/21

我有什么办法可以告诉 React,或者 React 会知道自己,在这个 setState 之后,另一个 setState 即将出现,所以跳过重新渲染,直到你找到一秒钟的呼吸时间。

你不能,React 批处理(如 React 17(仅在事件处理程序和生命周期方法上更新状态,因此不可能像您的情况一样在承诺中进行批处理。

要解决这个问题,您需要将钩子状态减少到单个源。

从 React 18 开始,即使在承诺中,您也可以自动批处理。

REACT 18 更新

在 React 18 中,所有一起发生的状态更新都会自动批处理到单个渲染中。这意味着可以将状态拆分为任意数量的单独变量。

来源: 反应 18 批处理

相关内容

  • 没有找到相关文章

最新更新