You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复模拟dispatch时useDispatch React Hook被条件调用的问题

解决React Hook "useDispatch"被条件调用的错误

问题根源

你在组件的props默认值里直接调用了useDispatch():

_useDispatch = useDispatch() // 这里违反了Hook规则

React要求Hook必须在组件顶层、每次渲染都按相同顺序调用,而props默认值的执行时机不确定——当父组件传入_useDispatch时,这个默认值里的Hook调用会被跳过,导致不同渲染中Hook调用顺序不一致,触发报错。

修复步骤

  1. 修改组件的props默认值:把useDispatch()改成useDispatch(传递Hook函数本身,不立即调用)
  2. 在组件顶层调用Hook:在函数体内统一调用_useDispatch()获取dispatch方法

修改后的组件代码:

import { Stage } from "../Stage/Stage";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
import { retrieveStageList } from "../../modules/reducer";
import { Process } from "../Process/Process";

export function RenderProcess({
  _useSelector = useSelector,
  _useDispatch = useDispatch, // 只传函数,不调用
  _Process = Process,
}) {
  const dispatch = _useDispatch(); // 在组件顶层调用,符合Hook规则
  const process = _useSelector((state) => state.renderProcess);
  const stageList = _useSelector((state) => state.stageList);
  
  useEffect(() => {
    if (process.processId !== null)
      dispatch(retrieveStageList(process.processId));
  }, [dispatch, process.processId]); // 补充依赖,避免旧闭包问题

  return (
    <>
      <_Process process={process} />
      {stageList?.map((stageInputs, processId) => {
        return (
          <div key={processId}>
            <Stage stage={stageInputs} />
          </div>
        );
      })}
    </>
  );
}

额外说明:useEffect的依赖数组要加上dispatch和process.processId,避免因为闭包导致的逻辑错误(React Redux的dispatch本身是稳定的,但显式声明依赖更规范)。

测试代码无需调整

测试中传入的_useDispatch会返回模拟的dispatch函数,组件现在会调用传入的_useDispatch获取dispatch,原测试代码可以正常运行:

import { render } from "@testing-library/react";
import { RenderProcess } from "./RenderProcess";

test("should call dispatch once.", () => {
  const _useSelector = (fn) =>
    fn({
      stageList: [],
      renderProcess: { processId: "309624b6-9c96-4ba7-8f7e-78831614f685" },
    });
  
  const dispatch = jest.fn();
  render(
    <RenderProcess
      _useSelector={_useSelector}
      _useDispatch={() => dispatch}
      _Process={() => {}}
    />
  );
  expect(dispatch).toHaveBeenCalledTimes(1);
});

这样修改后,不管是正常运行还是测试模拟,都能符合React Hook的规则,解决报错问题。

内容的提问来源于stack exchange,提问作者Callie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 11:01:06