【问题标题】:Issue React Hooks is called conditionally. React Hooks must be called in the exact same order in every component render有条件地调用 Issue React Hooks。 React Hooks 必须在每个组件渲染中以完全相同的顺序调用
【发布时间】:2022-12-09 18:19:23
【问题描述】:

我有问题,在使用三元运算符检查要使用哪个 React Hook 时出现错误。 消息是:“有条件地调用 React Hook“useIsolationDynamicPhase”。必须在每个组件渲染中以完全相同的顺序调用 React Hooks。” 有没有人发生并且知道如何解决它。

谢谢你。

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>
    );
}

我在许多网站上阅读了一些解决方案,但我找不到适合这种情况的解决方案。在这种情况下,我只想调用一个反应挂钩。

【问题讨论】:

标签: javascript reactjs typescript web web-frontend


【解决方案1】:

您绝对必须以一致的顺序为每个组件调用您的钩子,尤其是useState。你真的不能有条件地使用它们。

我不知道 useIsolationDynamicPhaseuseIsolationPhase 做什么,但我怀疑他们有自己的内部 useState 调用。如果是这种情况,您需要确保无论您是否需要,它们都会在每次迭代中被调用。

所以不是这个:

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

考虑一下:

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;

【讨论】:

    【解决方案2】:

    在顶层使用两个钩子,检查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>
        );
    }
    

    希望能帮助到你

    【讨论】:

      猜你喜欢
      • 2020-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-16
      • 2020-01-15
      • 2020-10-26
      相关资源
      最近更新 更多