diff --git a/examples/react/package.json b/examples/react/package.json
index 24bbee4a..6b7362f5 100644
--- a/examples/react/package.json
+++ b/examples/react/package.json
@@ -14,13 +14,16 @@
"test-e2e": "start-server-and-test 'pnpm serve' http-get://localhost:3000 'pnpm test-e2e-cypress'"
},
"dependencies": {
+ "@reduxjs/toolkit": "^2.2.3",
"@xyflow/react": "workspace:*",
"classcat": "^5.0.4",
"dagre": "^0.8.5",
"localforage": "^1.10.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-redux": "^9.1.1",
"react-router-dom": "^6.18.0",
+ "redux": "^5.0.1",
"zustand": "^4.4.6"
},
"devDependencies": {
diff --git a/examples/react/src/App/routes.ts b/examples/react/src/App/routes.ts
index 1d68c858..287ab17b 100644
--- a/examples/react/src/App/routes.ts
+++ b/examples/react/src/App/routes.ts
@@ -51,6 +51,7 @@ import UseNodesData from '../examples/UseNodesData';
import UseHandleConnections from '../examples/UseHandleConnections';
import AddNodeOnEdgeDrop from '../examples/AddNodeOnEdgeDrop';
import DevTools from '../examples/DevTools';
+import Redux from '../examples/Redux';
export interface IRoute {
name: string;
@@ -314,6 +315,11 @@ const routes: IRoute[] = [
path: 'useupdatenodeinternals',
component: UseUpdateNodeInternals,
},
+ {
+ name: 'redux',
+ path: 'redux',
+ component: Redux,
+ },
{
name: 'Validation',
path: 'validation',
diff --git a/examples/react/src/examples/NodeResizer/index.tsx b/examples/react/src/examples/NodeResizer/index.tsx
index 7afb411f..8d5b7602 100644
--- a/examples/react/src/examples/NodeResizer/index.tsx
+++ b/examples/react/src/examples/NodeResizer/index.tsx
@@ -185,6 +185,7 @@ const CustomNodeFlow = () => {
maxZoom={5}
snapToGrid={snapToGrid}
fitView
+ onlyRenderVisibleElements
>
diff --git a/examples/react/src/examples/Redux/index.tsx b/examples/react/src/examples/Redux/index.tsx
new file mode 100644
index 00000000..19bbd90c
--- /dev/null
+++ b/examples/react/src/examples/Redux/index.tsx
@@ -0,0 +1,30 @@
+import { ReactFlow } from '@xyflow/react';
+import '@xyflow/react/dist/style.css';
+
+import { useDispatch, useSelector, Provider } from 'react-redux';
+
+import { onNodesChange, onEdgesChange, setSelectedNodesAndEdges, store } from './state';
+
+const OverviewFlow = () => {
+ const dispatch = useDispatch();
+ const nodes = useSelector((state) => state.myApplication.nodes);
+ const edges = useSelector((state) => state.myApplication.edges);
+
+ return (
+ dispatch(onNodesChange(e))}
+ onEdgesChange={(e) => dispatch(onEdgesChange(e))}
+ onSelectionChange={(e) => dispatch(setSelectedNodesAndEdges(e))}
+ fitView
+ attributionPosition="top-right"
+ />
+ );
+};
+
+export default () => (
+
+
+
+);
diff --git a/examples/react/src/examples/Redux/initial-elements.tsx b/examples/react/src/examples/Redux/initial-elements.tsx
new file mode 100644
index 00000000..136583cf
--- /dev/null
+++ b/examples/react/src/examples/Redux/initial-elements.tsx
@@ -0,0 +1,98 @@
+import { MarkerType, type Node, type Edge } from '@xyflow/react';
+
+export const nodes: Node[] = [
+ {
+ id: '1',
+ type: 'input',
+ data: {
+ label: 'hey',
+ },
+ position: { x: 250, y: 0 },
+ },
+ {
+ id: '2',
+ data: {
+ label: 'default node',
+ },
+ position: { x: 100, y: 100 },
+ },
+ {
+ id: '3',
+ data: {
+ label: 'custom style',
+ },
+ position: { x: 400, y: 100 },
+ style: {
+ background: '#D6D5E6',
+ color: '#333',
+ border: '1px solid #222138',
+ width: 180,
+ },
+ },
+ {
+ id: '4',
+ position: { x: 250, y: 200 },
+ data: {
+ label: 'Another default node',
+ },
+ },
+ {
+ id: '5',
+ data: {
+ label: 'Node id: 5',
+ },
+ position: { x: 250, y: 325 },
+ },
+ {
+ id: '6',
+ type: 'output',
+ data: {
+ label: 'output',
+ },
+ position: { x: 100, y: 480 },
+ },
+ {
+ id: '7',
+ type: 'output',
+ data: { label: 'Another output node' },
+ position: { x: 400, y: 450 },
+ },
+];
+
+export const edges: Edge[] = [
+ { id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
+ { id: 'e1-3', source: '1', target: '3' },
+ {
+ id: 'e3-4',
+ source: '3',
+ target: '4',
+ animated: true,
+ label: 'animated edge',
+ },
+ {
+ id: 'e4-5',
+ source: '4',
+ target: '5',
+ label: 'edge with arrow head',
+ markerEnd: {
+ type: MarkerType.ArrowClosed,
+ },
+ },
+ {
+ id: 'e5-6',
+ source: '5',
+ target: '6',
+ type: 'smoothstep',
+ label: 'smooth step edge',
+ },
+ {
+ id: 'e5-7',
+ source: '5',
+ target: '7',
+ type: 'step',
+ style: { stroke: '#f6ab6c' },
+ label: 'a step edge',
+ animated: true,
+ labelStyle: { fill: '#f6ab6c', fontWeight: 700 },
+ },
+];
diff --git a/examples/react/src/examples/Redux/state.ts b/examples/react/src/examples/Redux/state.ts
new file mode 100644
index 00000000..7c7e93d2
--- /dev/null
+++ b/examples/react/src/examples/Redux/state.ts
@@ -0,0 +1,59 @@
+import { createSlice, configureStore } from '@reduxjs/toolkit';
+import { applyNodeChanges, applyEdgeChanges } from '@xyflow/react';
+import { nodes, edges } from './initial-elements';
+
+const initialState = {
+ nodes,
+ edges,
+ selectedNodes: [],
+ selectedEdges: [],
+};
+
+const setNodesReducer = (state, action) => {
+ state.nodes = action.payload;
+};
+
+const setEdgesReducer = (state, action) => {
+ state.edges = action.payload;
+};
+
+const onNodesChangeReducer = (state, action) => {
+ const a = applyNodeChanges(action.payload, state.nodes);
+ state.nodes = a;
+};
+
+const onEdgesChangeReducer = (state, action) => {
+ const a = applyEdgeChanges(action.payload, state.edges);
+ state.edges = a;
+};
+
+const setSelectedNodesAndEdgesReducer = (state, action) => {
+ state.selectedNodes = action.payload.nodes;
+ state.selectedEdges = action.payload.edges;
+};
+
+const setSelectedNodesReducer = (state, action) => {
+ state.selectedNodes = action.payload;
+};
+
+const MyApplicationSlice = createSlice({
+ name: 'MyApplication',
+ initialState,
+ reducers: {
+ setNodes: setNodesReducer,
+ setEdges: setEdgesReducer,
+ onNodesChange: onNodesChangeReducer,
+ onEdgesChange: onEdgesChangeReducer,
+ setSelectedNodesAndEdges: setSelectedNodesAndEdgesReducer,
+ setSelectedNodes: setSelectedNodesReducer,
+ },
+});
+
+export const { setNodes, setEdges, onNodesChange, onEdgesChange, setSelectedNodesAndEdges, setSelectedNodes } =
+ MyApplicationSlice.actions;
+
+export const store = configureStore({
+ reducer: {
+ myApplication: MyApplicationSlice.reducer,
+ },
+});
diff --git a/examples/svelte/src/routes/examples/reset/+page.svelte b/examples/svelte/src/routes/examples/reset/+page.svelte
index 78b1b245..e7857d70 100644
--- a/examples/svelte/src/routes/examples/reset/+page.svelte
+++ b/examples/svelte/src/routes/examples/reset/+page.svelte
@@ -1,14 +1,6 @@