Home > other >  Issue React Hooks is called conditionally. React Hooks must be called in the exact same order in eve
Issue React Hooks is called conditionally. React Hooks must be called in the exact same order in eve

Time:12-09

I have problem that i get an error when using the ternary operator to check which React Hook to use. The message is:"React Hook "useIsolationDynamicPhase" is called conditionally. React Hooks must be called in the exact same order in every component render." Do anyone happen and know how to fix it.

Thank you.

export default function Edit({ isPhasedIsolation }: Props) {
    const { phaseId, methodId } = useParams<{ phaseId: string; methodId: string }>();
    const method = isPhasedIsolation ? usePhaseMethod( phaseId,  methodId) : useMethod( phaseId,  methodId);
    const phase = isPhasedIsolation ? useIsolationDynamicPhase( phaseId) :  useIsolationPhase( phaseId);
    const [checked, setChecked] = useState<boolean>(Boolean(method?.currentState));
    const save = useSave(method as IsolationMethod,  phaseId, checked, phase?.phaseType as string, isPhasedIsolation);

    if (method === null) return null;

    return (
        <EditTabLayout
            onSave={save}
            disableSaveButton={Boolean(method?.currentState) === checked}
            title={`${getLabel('button.label.update')} ${getLabel('print.activity.status')}`}>
            <Container>
                <DisplayField label={getLabel('mobile.isolation.plannedState')}>
                    <TruncatedText text={method.plannedState} />
                </DisplayField>
            </Container>
            <Container>
                <Row>
                    <Label>{getLabel('dashboard.activityGrid.column.currentState')}</Label>
                    <Switch checked={checked} onChange={e => setChecked(e.value)} />
                </Row>
            </Container>
        </EditTabLayout>
    );
}

I have read some solution in many website but i can not find out the suitable solution for this situation. I want only one react hook is called in this case.

CodePudding user response:

You absolutely have to call your hooks, especially useState in a consistent order for each component. You really can't use them conditionally.

I don't know what useIsolationDynamicPhase or useIsolationPhase do, but I suspect they have their own internal useState calls. If that's the case, you need to make sure they get called on each iteration whether your need it or not.

So instead of this:

const phaseMethod = isPhasedIsolation ? usePhaseMethod( phaseId,  methodId) : useMethod( phaseId,  methodId);
const phase = isPhasedIsolation ? useIsolationDynamicPhase( phaseId) :  useIsolationPhase( phaseId);

Consider this:

const methodPhase = usePhaseMethod( phaseId,  methodId);
const methodNormal = useMethod( phaseId,  methodId);
const dynamicPhase = useIsolationDynamicPhase( phaseId);
const isolationPhase = useIsolationPhase( phaseId);

const method = isPhasedIsolation ? methodPhase : methodNormal;
const phase = isPhasedIsolation ? dynamicPhase : isolationPhase;

CodePudding user response:

Use both hooks at top level, check rules of hooks

export default function Edit({ isPhasedIsolation }: Props) {

    const { phaseId, methodId } = useParams<{ phaseId: string; methodId: string }>();

   // use both hooks at top level
   const phaseMethod = usePhaseMethod( phaseId,  methodId);
   const otherMethod = useMethod( phaseId,  methodId);
   const method = isPhasedIsolation ? phaseMethod : otherMethod;

   const isolationPhase = useIsolationDynamicPhase( phaseId);
   const otherPhase =  useIsolationPhase( phaseId);
   const phase = isPhasedIsolation ? isolationPhase : otherPhase;

    const [checked, setChecked] = useState<boolean>(Boolean(method?.currentState));

    const save = useSave(method as IsolationMethod,  phaseId, checked, phase?.phaseType as string, isPhasedIsolation);

    if (method === null) return null;

    return (
        <EditTabLayout
            onSave={save}
            disableSaveButton={Boolean(method?.currentState) === checked}
            title={`${getLabel('button.label.update')} ${getLabel('print.activity.status')}`}>
            <Container>
                <DisplayField label={getLabel('mobile.isolation.plannedState')}>
                    <TruncatedText text={method.plannedState} />
                </DisplayField>
            </Container>
            <Container>
                <Row>
                    <Label>{getLabel('dashboard.activityGrid.column.currentState')}</Label>
                    <Switch checked={checked} onChange={e => setChecked(e.value)} />
                </Row>
            </Container>
        </EditTabLayout>
    );
}

Hope it helps

  • Related