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

React+XState项目:无法从Editor子组件更新bookmarkMachine上下文

问题

我正在使用React和XState开发一款网站构建器应用。父组件<SkinsController>(代码中写为SkiController)使用状态机bookmarkMachine管理书签状态,子组件<Editor>有自己的状态机editorMachine负责编辑书签属性。

当用户在<Editor>中保存修改时,我希望向bookmarkMachine发送事件,创建带有更新属性的新书签,但bookmarkMachine的上下文并未更新,也没有报错信息。

以下是简化代码:

import { assign, createMachine } from "xstate";

export const bookmarkMachine = createMachine({
  id: "bookmark",
  initial: "idle",
  context: {
    bookmarks: [],
  },
  states: {
    idle: {
      on: {
        CREATE_BOOKMARK: {
          actions: assign((context, event) => {
            const newBookmark = {
              id: event.id,
              inputValue: event.inputValue,
              hState: event.hState,
              satState: event.satState,
              liState: event.liState,
              imageURL: event.imageURL,
            };
            context.bookmarks.push(newBookmark);
          }),
        },
      },
    },
  },
});

import React, { useState } from "react";
import Editor from "./Editor";
import { useMachine } from "@xstate/react";
import { bookmarkMachine } from "../machines/bookmarkMachine";

export default function SkiController() {
  const [component, setComponent] = useState(null);
  const [state, send] = useMachine(bookmarkMachine);
  const handleClick = (componentNumber) => {
    setComponent(componentNumber);
  };

  return (
    <div className="sController">
      <div className="leftContainer">
        {component === 1 && <Editor sendBookmarks={send} />}
      </div>
    </div>
  );
}

import React from "react";
import { useMachine } from "@xstate/react";
import Rename from "./Rename";
import { editorMachine } from "../machines/editorMachine";

const Editor = ({ sendBookmarks }) => {
  const [state, send] = useMachine(editorMachine);
  const handleOpenRename = () => send("OPEN_RENAME");
  const handleCloseRename = () => send("CLOSE_RENAME");

  const handleSaveName = async (newName) => {
    send({ type: "SAVE_NAME", value: newName });

    sendBookmarks({
      type: "CREATE_BOOKMARK",
      id: newName,
      inputValue: newName,
      hState: state.context.hState,
      satState: state.context.satState,
      liState: state.context.liState,
    });
  };

  return (
    <div className="Editor draggable">
      <button onClick={handleOpenRename}>Rename</button>
      <Rename
        isOpen={state.matches("renaming")}
        onClose={handleCloseRename}
        onSave={handleSaveName}
      />
    </div>
  );
};

export default Editor;
解决方案
  • 保持上下文不可变性:XState依赖不可变更新来追踪上下文变化,你当前直接用context.bookmarks.push(newBookmark)修改原数组,XState无法识别这个变化。需要返回一个新的数组对象:
actions: assign((context, event) => {
  const newBookmark = {
    id: event.id,
    inputValue: event.inputValue,
    hState: event.hState,
    satState: event.satState,
    liState: event.liState,
    imageURL: event.imageURL,
  };
  // 返回新的上下文对象,包含新的书签数组
  return {
    bookmarks: [...context.bookmarks, newBookmark]
  };
}),
  • 补全事件参数:发送CREATE_BOOKMARK事件时缺少imageURL参数,虽然不会直接导致上下文不更新,但可能引发后续逻辑问题,建议补充该参数或者根据业务需求调整newBookmark的字段定义。

  • 验证事件接收状态:可以在SkiController中打印当前书签列表,确认事件是否被正确接收和处理:

// 在SkiController组件内添加
console.log('当前书签:', state.context.bookmarks);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:47:46