React无限重渲染错误解决:角色权限控制场景
解决React组件无限重渲染问题(角色判断导致)
错误原因
你直接在组件渲染阶段调用setRole修改状态:每次组件渲染时,都会执行roles?.map里的逻辑并触发setRole,状态更新会再次触发组件渲染,形成无限循环,最终触发React的重渲染限制错误。
另外你的map逻辑还有漏洞:如果角色数组里有多个角色,只要最后一个不是LINACAPPOINTMENTMANAGER,role会被覆盖为false,哪怕前面有目标角色也会失效。
解决方案
不需要用useState存储角色判断结果,直接在渲染时计算即可(如果角色可能动态变化,用useMemo缓存结果):
方案1:直接计算(角色无动态变化场景)
替换原来的useState和map代码段,直接判断是否包含目标角色:
const authContext = useContext(AuthContext); const roles = authContext.userData?.roleNames; // 直接判断数组是否包含目标角色,默认返回false const hasLinacManagerRole = roles?.includes('LINACAPPOINTMENTMANAGER') || false;
然后修改FormElement的disabled属性:
<FormElement {...sharedProps} type='select' label='selectmachineProposal' name='machine' options={machineQuery.data?.items} disabled={!hasLinacManagerRole} // 有角色则禁用为false(启用字段),无则为true(禁用字段) />
方案2:用useMemo缓存(角色可能动态变化场景)
如果角色会在组件生命周期中动态更新(比如用户切换角色),用useMemo缓存计算结果,避免不必要的重复计算:
import { FunctionComponent, useContext, useMemo } from 'react'; // 引入useMemo // ... const authContext = useContext(AuthContext); const roles = authContext.userData?.roleNames; // 仅当roles变化时重新计算结果 const hasLinacManagerRole = useMemo(() => { return roles?.includes('LINACAPPOINTMENTMANAGER') || false; }, [roles]);
FormElement的disabled属性同上。
完整修改后的组件代码
import { Col, Divider, Row } from 'antd'; import moment from 'moment'; import { FunctionComponent, useContext, useMemo } from 'react'; import { useIntl } from 'react-intl'; import { useQuery } from 'react-query'; import index from '../../../../../api/nuclearMedicineApi/services/Index'; import Machine from '../../../../../api/nuclearMedicineApi/services/Machine'; import { dateFormat } from '../../../../../constants'; import { Index, MachineCategory, Priority, RadioTherapyByLinactStates } from '../../../../../constants/enums'; import { AuthContext } from '../../../../../contexts/auth-context'; import { IFormProps } from '../../../../../interfaces/form-props'; import { mapEnumToSelectValues } from '../../../../../utils/map-enum'; import FormElement from '../../../../common/form-element'; import StepsDiv from '../../../../common/steps'; interface RadioTherapyByLinacFormProps extends IFormProps { } const RadioTherapyByLinacForm: FunctionComponent<RadioTherapyByLinacFormProps> = ({ control, disabled, type, data }) => { const sharedProps = { control, disabled, }; const authContext = useContext(AuthContext); const roles = authContext.userData?.roleNames; const hasLinacManagerRole = useMemo(() => { return roles?.includes('LINACAPPOINTMENTMANAGER') || false; }, [roles]); const machineQuery = useQuery('machineGetAllLite', () => Machine.machineGetAllLite({ machineCategory: MachineCategory.RadioTherapyByLinac }), ); return ( <> <Row> <Col span={12}> <FormElement {...sharedProps} type='select' label='selectmachineProposal' name='machine' options={machineQuery.data?.items} disabled={!hasLinacManagerRole} /> </Col> </Row> </> ); }; export default RadioTherapyByLinacForm;
内容的提问来源于stack exchange,提问作者Hiba Youssef
相关产品推荐
相关产品推荐

