Witam,
korzystam z React-Flow i stworzyłem diagram interaktywny. Jednaest wewnątrz komponentu, a ja chciałbym ją przenieść do osobnych plików. Jednak problem w tym, że te funkcje korzystają z hooków. Tak więc może ktoś mi podpowie jak przenieść funkcje getChildNodePosition
, onConnectEnd
do osobnych plików?
Niby można wszystkie zależności przekazać w parametrach, ale wtedy było by ich z 10. Zamiast tego wolałbym na przykład wywołać const store = useStoreApi();
w osobnym pliku i na tym operować.
import React, {useCallback, useRef} from 'react';
import ReactFlow, {Controls, Panel, useStoreApi, useReactFlow, ConnectionLineType} from 'reactflow';
import {addChildNode, onEdgesChange, onNodesChange} from '../store/slices/mindMapSlice';
import {useDispatch, useSelector} from 'react-redux';
import MindMapNode from './Utils/MindMapNode';
import MindMapEdge from './Utils/MindMapEdge';
// we need to import the React Flow styles to make it work
import 'reactflow/dist/style.css';
const nodeTypes = {
mindmap: MindMapNode,
};
const edgeTypes = {
mindmap: MindMapEdge,
};
const nodeOrigin = [0.5, 0.5];
const connectionLineStyle = {stroke: '#F6AD55', strokeWidth: 3};
const defaultEdgeOptions = {style: connectionLineStyle, type: 'mindmap'};
export default function MindMap() {
const dispatch = useDispatch();
const {nodes, edges} = useSelector((state) => state.mindmap);
const connectingNodeId = useRef(null);
const store = useStoreApi();
const {project} = useReactFlow();
const getChildNodePosition = (event, parentNode) => {
const {domNode} = store.getState();
if (!domNode || !parentNode?.positionAbsolute || !parentNode?.width || !parentNode?.height) {
return;
}
const {top, left} = domNode.getBoundingClientRect();
const panePosition = project({
x: event.clientX - left,
y: event.clientY - top,
});
return {
x: panePosition.x - parentNode.positionAbsolute.x + parentNode.width / 2,
y: panePosition.y - parentNode.positionAbsolute.y + parentNode.height / 2,
};
};
const onConnectStart = useCallback((_, {nodeId}) => {
connectingNodeId.current = nodeId;
}, []);
const onConnectEnd = useCallback(
(event) => {
const {nodeInternals} = store.getState();
const targetIsPane = event.target.classList.contains('react-flow__pane');
const node = event.target.closest('.react-flow__node');
if (node) {
node.querySelector('input')?.focus({preventScroll: true});
} else if (targetIsPane && connectingNodeId.current) {
const parentNode = nodeInternals.get(connectingNodeId.current);
const childNodePosition = getChildNodePosition(event, parentNode);
if (parentNode && childNodePosition) {
dispatch(addChildNode({parentNode, childNodePosition}));
}
}
},
[getChildNodePosition]
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={(d) => dispatch(onNodesChange(d))}
onEdgesChange={(d) => dispatch(onEdgesChange(d))}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
onConnectStart={onConnectStart}
onConnectEnd={onConnectEnd}
connectionLineStyle={connectionLineStyle}
defaultEdgeOptions={defaultEdgeOptions}
connectionLineType={ConnectionLineType.Straight}
nodeOrigin={nodeOrigin}
fitView
>
<Controls showInteractive={false} />
<Panel position="top-left" className="header">
React Flow Mind Map
</Panel>
</ReactFlow>
);
}