Home > other >  Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop
Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop

Time:01-04

I have a project, and within this project I have several interfaces, and among these interfaces, I have an interface for creating a request, and this interface contains a field, and this field can be "disabled" or "not be disabled", when the role is "LINACAPPOINTMENTMANAGER" the field must be "disabled" Unless it's Enable.

And the role is an array of roles, that is, the user may have several roles and not just one role, and all roles must be traversed To check if the matrix contains an "LINACAPPOINTMENTMANAGER" role or not

I used "useState" named "role" and if the user is "LINACAPPOINTMENTMANAGER" it becomes true or false and on this basis I treat disabled

but i get this error:

Too many re-renders. React limits the number of renders to prevent an infinite loop.

How can i solve this problem?

import { Col, Divider, Row } from 'antd';
import moment from 'moment';
import { FunctionComponent, useContext, useState } 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;

    console.log('authContext: ', roles);
    const [role, setRole] = useState(false);
    {
        roles?.map((r: string, index) => {
            if (r === 'LINACAPPOINTMENTMANAGER') {
                setRole(true);
            }
            else {
                setRole(false);
            }
        })
    }


    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={role === true ? false : true}
                    />
                </Col>

            </Row>
        </>
    );
};

export default RadioTherapyByLinacForm;

// mapper for
//creatorUserId: 2
//lastModifierUserId: null

CodePudding user response:

Maybe put the map in a useEffect would work?

useEffect(() => {
   roles.forEach((r: string) => setRole(r === 'LINACAPPOINTMENTMANAGER'))
}, [roles])

Can you also clarify, if the role LINACAPPOINTMENTMANAGER is found, then the setRole is immediate true right? If that's the case, then forEach would not work because the loop will continue and might set it to false again if the next element is not LINACAPPOINTMENTMANAGER. In such case some would be the appropriate method.

CodePudding user response:

Why do you get this error?

When the component is rendered you're checking the roles array for your specific role. As long as your roles array is not empty, the setRole() function is called within map(). Attention: Updating a components state triggers a re-render of the component.

So the component gets re-rendered and again you come to the point where the roles array is checked and setRole() is called which triggers a re-render. And so on and so forth.

To avoid the rendering loop, put the setRole function in a useEffect that gets called only initially and if roles change.

How to solve the issue?

Update the components state only at first render or if the roles array has changed.

useEffect(()=>{
   let isManager = roles.some((r: string) => r === 'LINACAPPOINTMENTMANAGER');
   setRole(isManager);
}, [roles]);

React documentation

Here is an example from the React documentation that addresses the effect of a state change: https://reactjs.org/docs/hooks-state.html#recap

CodePudding user response:

You can use useEffect.

useEffect(() => {
  const unrole = roles.forEach((r: string) => setRole(r === 'LINACAPPOINTMENTMANAGER'))

  //unmounting
  return unrole
}, [roles])
  • Related