为什么react组件得到了太多的重新渲染



我不是新手,但出于某种原因,我喜欢它。

我的react组件正在无限地重新渲染:

const [apiDetails, setApiDetails] = useState({});
const { onboardApi, fetchOneApi } = useActions();
// get apiDetails from the redux store
const { apiList } = useSelector((state) => state.marketplace);
console.log('api list', apiList);
/* 
* if I move this block inside useEffect's if condition, 
* it fixes it but the state is not getting changed 
*/
if (apiList && apiList[apiId]) {
setApiDetails((oldState) => ({ ...oldState, ...apiList[apiId] })); 
}

useEffect(() => {
// fetch the api details to show dropdown options
if (!implementation) {
fetchOneApi(apiId);
}
}, [implementation]);

CCD_ 1被进一步传递给子组件。

implemention来自路由器:

<Route
path="/implementation/:id"
exact
render={(props) => <OnboardPage {...props} implementation={true} />}
/>
if (apiList && apiList?[apiId]) {
setApiDetails((oldState) => ({ ...oldState, ...apiList[apiId] })); 
}

问题在于代码的上述部分。

每次渲染组件时,if块都会运行并更新状态。当状态更新时,组件将再次渲染。if再次运行,另一个状态更改,另一次渲染。因此,您的无限渲染。将其移动到一个单独的useEffect中,该useEffect与您已经使用的效果不同。

永远不要在组件的主函数体中设置状态,将其封装在另一个嵌套函数中,并根据要求从一个或多个事件处理程序(onClick or onChange(调用该函数,或将其放置在推荐的useEffect()

useEffect(() => { 
if (apiList?.[apiId]) {
setApiDetails((oldState) => ({ ...oldState, ...apiList[apiId] })); 
}
}, [apiId])

您可以通过不传递查询参数apiId来验证当前实现的上述行为,在这种情况下,if语句将不会运行,组件状态也不会更新。所以,没有额外的渲染,没有无限循环。

此外,您可以只传递一个空数组[]作为useEffect的第二个参数,而不是[apiId],因为apiId是根据您的注释从查询参数中提取的。因此,当组件渲染时,它要么是已定义的,要么是未定义的,并且在组件的生命周期内不太可能更改。[]保证if语句只在组件装载后立即运行一次。

最后,如果您的设置支持ES2020试用可选链接,那么它对null检查非常方便。您将编写较少的代码。