【问题标题】: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。你真的不能有条件地使用它们。
我不知道 useIsolationDynamicPhase 或 useIsolationPhase 做什么,但我怀疑他们有自己的内部 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>
);
}
希望能帮助到你