为什么 React props 没有在事件处理程序中更新

Why are React props not updated in event handler

我有一个使用 useEffect 挂钩订阅外部事件的功能组件,并且该外部事件正在使用组件属性中的值。我不明白为什么组件本身在渲染时使用更新的 prop 值,但我的回调使用原始值。

我想也许我需要更改 useEffect 的第二个参数来指定道具,但这没有任何区别。

在下面的示例中,onSave 回调被调用并尝试使用 props.modelName 的当前值,但是,即使组件本身具有更新的值回调似乎只能看到 属性.

的原始值

这是为什么?它与关闭有关还是我遗漏了其他东西?

useEffect(() => {
    EventBus.on(EventIds._designerSaveCommand, onSave);

    return () => {
      EventBus.remove(EventIds._designerSaveCommand, onSave);
    };
  }, [reactFlowInstance,props]);

我的事件处理程序是这样的:

const onSave = () => {
    try {
      const object = reactFlowInstance?.toObject();

      if(object) {
        const exportedModel: IExportedModel = {
          modelName: props.modelName,  <---- This is not the current value in the component props
          model: object
        };

        const json = JSON.stringify(exportedModel);
        var blob = new Blob([json], { type: "application/json" });
        FileSaver.saveAs(blob, `${props.modelName}.json`);
      }
    }
    catch(e) {
      setMessage({text: e.message, type: MessageBarType.error});
    }
  };

你的想法是正确的,将 prop 添加到依赖项数组。您还需要将函数 onSave() 移动到钩子内部。然后它将引用最新的 modelName.

useEffect(() => {
  const onSave = () => {
    try {
      const object = reactFlowInstance?.toObject();
      if(object) {
        const exportedModel: IExportedModel = {
          modelName: modelName,
          model: object
        };

      const json = JSON.stringify(exportedModel);
        var blob = new Blob([json], { type: "application/json" });
        FileSaver.saveAs(blob, `${modelName}.json`);
      }
    }
    catch(e) {
      setMessage({text: e.message, type: MessageBarType.error});
    }
  };

  EventBus.on(EventIds._designerSaveCommand, onSave);

  return () => {
    EventBus.remove(EventIds._designerSaveCommand, onSave);
  };
}, [reactFlowInstance, modelName]);

如果你不喜欢 useEffect 这么大,你可以只将文件逻辑分离到一个新函数中,然后像这样在 hook 中调用它:

  useEffect(() => {
    const onSave = () => {
      saveFile(reactFlowInstance, modelName)
    };
    // ... handlers go here
  }, [reactFlowInstance, modelName]);