xyflow / xyflow

React Flow | Svelte Flow - Powerful open source libraries for building node-based UIs with React (https://reactflow.dev) or Svelte (https://svelteflow.dev). Ready out-of-the-box and infinitely customizable.
https://xyflow.com
MIT License
24.97k stars 1.61k forks source link

zustand error #2013

Closed Jasminou closed 2 years ago

Jasminou commented 2 years ago

Describe the Bug

Hi, on latest. When I try to use useReactFlow as describde in save and restore example on your website. I got this error below: Error Seems like you have not used zustand provider as an ancestor.

let me know if I'm missing something thanks

Your Example Website or App

No response

Steps to Reproduce the Bug or Issue

I followed the save/restore example here: https://reactflow.dev/docs/examples/save-and-restore/ when i try to use useReactFlow() I got this error.

Expected behavior

As User I expect to not have error when using some feature of the lib

Screenshots or Videos

image

Platform

Additional context

No response

raarts commented 2 years ago

Don't know of this is relevant, but I just had the same error after upgrading to 10.0.6. Completely rebuilding the app fixed it.

moklick commented 2 years ago

Is the component where you want to use useReactFlow a child component of <ReactFlow /> or wrapped with the <ReactFlowProvider /> ?

Jasminou commented 2 years ago

@moklick yes it's wrapped with ReactFlowProvider like below

export const myComponent = (props) => {
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
  const [rfInstance, setRfInstance] = useState(null);
  const { setViewport } = useReactFlow();  // when I add this I've the error

  const onSave = useCallback(() => {
    if (reactflowInstance) {
      const flow = reactflowInstance.toObject();
      localStorage.setItem(flowKey, JSON.stringify(flow));
    }
  }, [reactflowInstance]);

  // ... 

  const onRestore = useCallback(() => {
    const restoreFlow = async () => {
      const flow = JSON.parse(localStorage.getItem(flowKey));

      if (flow) {
        const { x = 0, y = 0, zoom = 1 } = flow.viewport;
        setNodes(flow.nodes || []);
        setEdges(flow.edges || []);
        setViewport({ x, y, zoom });
      }
    };

    restoreFlow();
  }, [setEdges, setNodes, setViewport]);

   //...

  return (
    <ReactFlowProvider>
      <ReactFlow
        nodes={nodes}
        edges={edges}
        nodeTypes={nodeTypes}
        edgeTypes={edgeTypes}
        onNodeClick={onNodeClick}
        onPaneClick={onPaneClick}
        onInit={onInit}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        nodesDraggable={false}
        nodesConnectable={false}
        zoomOnScroll={false}
        zoomOnPinch={false}
        zoomOnDoubleClick={false}
        panOnDrag={false}
        minZoom={0.8}
        fitView
      ></ReactFlow>
    </ReactFlowProvider>
  );
};
moklick commented 2 years ago

The component where you are using the hook needs to be wrapped with the ReactFlowProvider. You need to move it one level up.

<ReactFlowProvider>
  <ComponentWhereYouAreUsingTheHook />
</ReactFlowProvider>
Jasminou commented 2 years ago

Ah ok thanks i will try that

Jasminou commented 2 years ago

moving it a level up works thanks again

0p3r4t0r commented 9 months ago

Here' s a link to the relevant docs for anyone who comes across this in the future.