0
0

【ReactFlow】Cannot assign to read only property 'width' of object '#<Object>' TypeError: Cannot assign to read only property 'width' of object '#<Object>'のエラーがでて画面の拡大縮小ができないときにしたこと

Last updated at Posted at 2024-08-15

エラー

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の設定で書き込みの設定がもしできるのであればそっちの方がきれいかもしれません。

  1. Core Concepts. React Flow. https://reactflow.dev/learn/concepts/core-concepts. 2

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0