Witam,
zadaję dość desperackie pytanie, ale myślę, że słuszne. Do sedna. W mojej bibliotece zarządzania stanem mam obiekt nodes
. Przechowuje on wszystkie węzły mojego wykresu (React-Flow
). Komponent CustomNode
jest komponentem renderującym konkretny węzeł w zależności od id
.
Problem
Problemem jest to, że (moim zdaniem) ten kod jest dość chaotyczny. Wydaje mi się, że można z nim zrobić coś, co poprawi jego przejrzystość, ale nie wiem do końca jak. Wydaje mi się, że logika jest pomieszana, a w szczególności zarządzania stanem.
Nie wiem, czy dobrze opisałem problem, więc w razie pytań proszę je zadawać.
Nie oczekuję gotowca, a raczej porad jak poprawić kod.
Kod komponentu:
import React, {useEffect, useLayoutEffect, useRef, useState} from 'react';
import {Handle, NodeToolbar} from 'reactflow';
import useBoundStore from '../../store/store';
import Toolbar from './Toolbar';
export default function CustomNode({id}) {
const inputRef = useRef(null);
const spanRef = useRef(null);
const [disabled, setDisabled] = useState(true);
const [nodes, updateNode] = useBoundStore((state) => [state.nodes, state.updateNode]);
const [currentNodeData, setCurrentNodeData] = useState({});
//Update current node data on change
useEffect(() => {
if (!nodes) return;
setCurrentNodeData(nodes.find((el) => el.id === id)?.data);
}, [nodes?.find((el) => el.id === id)?.data, id]);
//Auto-width on input value change
useLayoutEffect(() => {
inputRef.current.style.width = spanRef.current.offsetWidth + 'px';
}, [nodes?.find((el) => el.id === id)?.data?.label]);
//Focus label input on doubleclick
useEffect(() => {
if (disabled === true) return;
inputRef.current.focus();
}, [disabled]);
//Unfocus input when click outside
const onInputBlur = () => {
const selection = document.getSelection();
selection.removeAllRanges();
setDisabled(true);
};
return (
<div className="node" style={{background: currentNodeData?.color}} onDoubleClick={(e) => setDisabled(false)}>
<Toolbar data={currentNodeData} id={id} />
<div className="dragHandle">
<svg viewBox="0 0 24 24">
<path fill="#333" stroke="#333" strokeWidth="1" d="M15 5h2V3h-2v2zM7 5h2V3H7v2zm8 8h2v-2h-2v2zm-8 0h2v-2H7v2zm8 8h2v-2h-2v2zm-8 0h2v-2H7v2z" />
</svg>
</div>
<input
type="text"
value={currentNodeData?.label || ''}
onChange={(e) => updateNode({id, propety: 'label', value: e.target.value})}
onBlur={(e) => onInputBlur(e)}
disabled={disabled}
ref={inputRef}
/>
<Handle type="source" position="top" className="source" />
<span ref={spanRef} className="autoWidth">
{nodes?.find((el) => el.id === id)?.data?.label}
</span>
</div>
);
}