vasturiano / react-force-graph

React component for 2D, 3D, VR and AR force directed graphs
https://vasturiano.github.io/react-force-graph/example/large-graph/
MIT License
2.18k stars 281 forks source link

ReferenceError: window is not defined #155

Open redochka opened 4 years ago

redochka commented 4 years ago

Using this within a nextjs app and getting this error:

ReferenceError: window is not defined

I am just trying basic examples:

<ForceGraph2D graphData={genRandomTree()} width={444} height={1111} />
vasturiano commented 4 years ago

@redochka thanks for reaching out.

This is because nextjs is running in SSR (Server-Side Rendering) mode, which is not compatible with this module because it doesn't provide a window environment. You should bypass SSR when rendering a part of the React DOM that includes this component.

Further, if you're getting this error at import time, you should also turn the import into dynamic so it doesn't fail the build: https://nextjs.org/docs/advanced-features/dynamic-import

connorwaslo commented 4 years ago

If anybody else runs into this issue using react-force-graph with Gatsby like I did, here's how I fixed it.

Install https://github.com/gregberge/loadable-components

npm install @loadable/component

Create a component for your force graph (forceGraph.js)

import { ForceGraph2D } from "react-force-graph"

export default ForceGraph2D

And import it with loadable-components to use as seen in the documentation. const ForceGraph = loadable(() => import('./forceGraph'))

alitourani commented 4 years ago

Solved it Here https://github.com/vasturiano/react-force-graph/issues/136#issuecomment-664213307

ahmedhosny commented 3 years ago

Thanks - using loadable-components works for gatsby.

But I am having problems using the react Effect hook. I am trying to recreate this codepen (#25) but with loadable.

import loadable from '@loadable/component'
const ForceGraph2D = loadable(() => import('./forceGraph2d'))

function Graph(props) {
  const forceRef = useRef(null);
  useEffect(() => {
    forceRef.current.d3Force("charge").strength(-4000);
  });
  return (
    <ForceGraph2D
      graphData={props.graphData}
      ref={forceRef}
    />
  );
}

Error in the useEffect hook as forceRef.current is undefined. I am pretty sure this is caused by loadable but not sure exactly why. Any ideas or alternative solutions to changing d3Force settings?

Scott-Hickmann commented 3 years ago

What you can do is instead load your Graph functional component using loadable, and inside that file load ForceGraph2D with a regular import.

In your graph file (./components/graph):

import ForceGraph2D from 'react-force-graph-2d';

function Graph(props) {
  const forceRef = useRef(null);
  useEffect(() => {
    forceRef.current.d3Force("charge").strength(-4000);
  });
  return (
    <ForceGraph2D
      graphData={props.graphData}
      ref={forceRef}
    />
  );
}

Then where you call the graph in your app:

import loadable from '@loadable/component'
const Graph = loadable(() => import('./components/graph'))

function App() {
  [...]
  return (
    [...]
    <Graph graphData={graphData} />
    [...]
  )
}

I have tested the above solution with next/dynamic so hopefully this technique works with loadable as well.

corbanvilla commented 1 year ago

Anyone on a Next 13, make the component that uses the ForceGraph a client-side component, and dynamically render it from the server component.

I.e.

// ForceGraph.tsx
import ForceGraph2D from 'react-force-graph-2d';

...
// <return component using ForceGraph>
// page.tsx
const DynamicForceGraph = dynamic(() => import('./ForceGraph'), { ssr: false });

...

// <use <DynamicForceGraph> like any other react component>