状态管理

在本指南中,我们假设你已经了解 React Flow 的核心概念以及如何实现自定义节点。你还应该熟悉状态管理库的概念以及如何使用它们。

在本指南中,我们将介绍如何将 React Flow 与状态管理库 Zustand 结合使用。 我们将创建一个小应用程序,其中每个节点都有一个颜色选择器,用于更新其背景颜色。 在本指南中,我们将使用 Zustand,因为我们已经在 React Flow 内部使用了它,当然,你也可以使用任何其他库,如 Redux、Recoil或 Jotai。

正如你在之前的指南和示例中看到的,React Flow 可以轻松地使用本地组件状态来处理图表的节点和边。 例如,当你的应用程序不断扩展,你希望从节点内部改变状态时,情况就会变得更加复杂。为了避免通过节点数据字段向下传递函数,你可以使用 React 上下文 或添加状态管理库,如本指南中所述。

概念

  • Store(存储对象):Store 就是用来维持应用所有的 state 树的一个对象。改变 store 内 state 的唯一途径是对它 dispatch 一个 action。 Store 不是类。它只是有几个方法的对象。
  • State(状态):应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。
  • Hook:React 钩子函数
  • Action:要想更新 state 中的数据,你需要发起一个 action。Action 就是一个普通 JavaScript 对象用来描述发生了什么。action 就像是描述发生了什么的指示器。

安装 Zustand

如上所述,我们在本示例中使用了 Zustand。Zustand 有点像 Redux:你有一个中心 store,其中包含用于改变状态的 action(动作)和访问 state(状态)的 hook(钩子)。 你可以通过以下方式安装 Zustand:

bash
yarn add zustand

创建一个 Store

Zustand 可让你创建一个 hook,用于访问 store 的值和函数。 我们将节点和边以及 onNodesChangeonEdgesChangeonConnectsetNodessetEdges 函数放在 store 中,以获得图形的基本交互性:

这就是基本设置。 现在,我们有了一个带有节点和边的存储空间,它可以处理 React Flow 触发的更改(拖动、选择或删除节点或边)。当你查看 index.tsx 文件时,你会发现它保持得非常整洁。所有数据和动作现在都是 Store 的一部分,可以通过 useStore 钩子访问。

实现一个颜色改变动作

我们添加了一个新的 updateNodeColor 操作,用于更新特定节点的 data.color 字段。 为此,我们将节点 id 和新颜色传递给动作,遍历节点并用新颜色更新匹配的节点:

tsx
updateNodeColor: (nodeId: string, color: string) => {
set({
nodes: get().nodes.map((node) => {
if (node.id === nodeId) {
// 在这里创建一个新对象,以便通知 React Flow 有关更改的信息,这一点很重要。
return { ...node, data: { ...node.data, color } };
}
return node;
}),
});
};

现在可以像这样在 React 组件中使用这个新动作:

tsx
const updateNodeColor = useStore((s) => s.updateNodeColor);
...
<button onClick={() => updateNodeColor(nodeId, color)} />;

添加一个颜色选择器节点

在这一步中,我们将实现 ColorChooserNode 组件,并在用户更改颜色时调用 updateNodeColor。颜色选择器节点的自定义部分是颜色输入。

tsx
<input
type="color"
defaultValue={data.color}
onChange={(evt) => updateNodeColor(id, evt.target.value)}
className="nodrag"
/>

我们添加了 nodrag 类名,这样用户在更改颜色时就不会误拖动节点,并在 onChange 事件处理程序中调用 updateNodeColor

现在,你可以点击颜色选择器,更改节点的背景。