我对反应并不陌生,但出于某种原因,我喜欢它。
我的 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]);
apiDetails
进一步传递给子组件。
implemention
来自路由器:
<Route
path="/implementation/:id"
exact
render={(props) => <OnboardPage {...props} implementation={true} />}
/>
答案 0 :(得分:2)
if (apiList && apiList?[apiId]) {
setApiDetails((oldState) => ({ ...oldState, ...apiList[apiId] }));
}
问题在于您的代码的上述部分。
每次组件渲染时,if 块都会运行并更新状态。当状态更新时,组件再次呈现。 if 再次运行,另一个状态改变,另一个渲染。因此,您的无限渲染。将它移到一个单独的 useEffect 中,而不是你已经在使用的那个。
切勿在组件的主函数体中设置状态,将其包装在另一个嵌套函数中并根据要求从一个或多个事件处理程序 (onClick or onChange
) 调用该函数或将它们放在 {{3} } useEffect()
useEffect(() => {
if (apiList?.[apiId]) {
setApiDetails((oldState) => ({ ...oldState, ...apiList[apiId] }));
}
}, [apiId])
您可以通过简单地不传递查询参数 apiId
来验证当前实现的上述行为,在这种情况下,if 语句将不会运行并且您的组件状态不会更新。所以,没有额外的渲染,没有无限循环。
此外,您可以将空数组 []
作为第二个参数传递给 useEffect 而不是 [apiId]
,因为 apiId 是根据您的评论从查询参数中提取的。因此,当组件呈现时它要么是已定义的,要么是未定义的,并且在组件的生命周期内不太可能改变。 []
保证 if 语句只会在组件安装后立即运行一次。
最后,如果您的设置支持 ES2020,请尝试 recommended,这对于空检查非常方便。您将编写较少的代码。