エラー
Cannot assign to read only property 'width' of object '#<Object>'
TypeError: Cannot assign to read only property 'width' of object '#<Object>'
at applyChange (http://localhost:3000/static/js/bundle.js:99275:34)
at applyChanges (http://localhost:3000/static/js/bundle.js:99247:7)
at applyNodeChanges (http://localhost:3000/static/js/bundle.js:99310:10)
at http://localhost:3000/main.3efe227f07ece2d34852.hot-update.js:81:175
at valueFromValueOrUpdater (http://localhost:3000/static/js/bundle.js:86778:12)
at applyAction (http://localhost:3000/static/js/bundle.js:86789:22)
at http://localhost:3000/static/js/bundle.js:86842:7
at Object.replaceState (http://localhost:3000/static/js/bundle.js:88223:18)
at applyActionsToStore (http://localhost:3000/static/js/bundle.js:86839:9)
at queueOrPerformStateUpdate (http://localhost:3000/static/js/bundle.js:86858:5)
該当コード(再現)
以下、公式ドキュメント1を参考にして再現した該当コードです。
import { useCallback, useState } from 'react';
import { ReactFlow, applyEdgeChanges, applyNodeChanges } from '@xyflow/react';
import { useRecoilState } from 'recoil';
import '@xyflow/react/dist/style.css';
const initialNodes = [
{
id: '1',
type: 'input',
data: { label: 'Input Node' },
position: { x: 250, y: 25 },
},
{
id: '2',
// you can also pass a React component as a label
data: { label: <div>Default Node</div> },
position: { x: 100, y: 125 },
},
{
id: '3',
type: 'output',
data: { label: 'Output Node' },
position: { x: 250, y: 250 },
},
];
const initialEdges = [
{ id: 'e1-2', source: '1', target: '2' },
{ id: 'e2-3', source: '2', target: '3', animated: true },
];
function Flow() {
const [nodes, setNodes] = useRecoilState(initialNodes);
const [edges, setEdges] = useRecoilState(initialEdges);
const onNodesChange = useCallback(
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
[setNodes],
);
const onEdgesChange = useCallback(
(changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
[setEdges],
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
fitView
/>
);
}
export default Flow;
考えられる原因
nodeの中のmesuredの中のwidthが読み取り専用になっていることが原因でapplyChange関数内において書き換えができないこと。
なぜ読み取り専用になっているかはよく分かっていないが、useStateを使っている公式ドキュメント1ではエラーは出ないことからuseRecoilStateを使っていることが原因だと思っている。
解決するためにしたこと
mesured.widthとmesured.heightのプロパティをコピーして使うようにすることで書き換えも可能にした。
// ノードの変更を検知
const onNodesChange = useCallback(
async (changes: any) => {
// changes: "dimensions" | "remove" | "select" | "position"
setNodes((nodes) => {
const oldNodes = nodes.map(
(node) => ({
...node,
measured: {
width: node.measured?.width || 150,
height: node.measured?.height || 38,
}
})
);
return applyNodeChanges(changes, oldNodes);
});
},
[setNodes],
);
Recoilの設定で書き込みの設定がもしできるのであればそっちの方がきれいかもしれません。
-
Core Concepts. React Flow. https://reactflow.dev/learn/concepts/core-concepts. ↩ ↩2