Home > other >  Execute Function when a State Variable Changes inside of a useEffect() Hook
Execute Function when a State Variable Changes inside of a useEffect() Hook

Time:12-16

so I am trying to create a graph visualization front-end using Antv's G6 and React. I have this useState() variable and function as shown below:

const [hideNode, sethideNode] = useState("");
const hideN = () => {
    const node = graph.findById(hideNode);
    node.hide();
  };

The function is in charge of hiding the selected node. However, the problem with running this function as it is, is that it will raise the error TypeError: Cannot read properties of null (reading 'findById') because graph is assigned inside of the useEffect() hook, as shown below:

useEffect(() => {
    if (!graph) {
      graph = new G6.Graph();
      graph.data(data);
      graph.render();
      hideN();
    }
  }, []);

It only works as intended if I call the function hideN() inside of the useEffect() hook, otherwise outside of the useEffect() if I console.log(graph) the result would be undefined.

So I wanted to ask, is there a way I could have this function run when the state changes while inside of the useEffect(), or is there a better way to go about this. I'm sorry I am super new to React so still learning the best way to go about doing something. I'd appreciate any help you guys can provide.

Full code:

import G6 from "@antv/g6";
import React, { useEffect, useState, useRef } from "react";
import { data } from "./Data";
import { NodeContextMenu } from "./NodeContextMenu";

const maxWidth = 1300;
const maxHeight = 600;

export default function G1() {
  let graph = null;
  const ref = useRef(null);

  //Hide Node State
  const [hideNode, sethideNode] = useState("");
  
  const hideN = () => {
    const node = graph.findById(hideNode);
    node.hide();
  };

  useEffect(() => {
    if (!graph) {
      graph = new G6.Graph(cfg);
      graph.data(data);
      graph.render();
      hideN();
    }
  }, []);

  return (
    <div>
      <div ref={ref}>
        {showNodeContextMenu && (
          <NodeContextMenu
            x={nodeContextMenuX}
            y={nodeContextMenuY}
            node={nodeInfo}
            setShowNodeContextMenu={setShowNodeContextMenu}
            sethideNode={sethideNode}
          />
        )}
      </div>
    </div>
  );
}

export { G1 };

CodePudding user response:

Store graph in a React ref so it persists through rerenders. In hideN use an Optional Chaining operator on graphRef.current to call the findById function.

Add hideNode state as a dependency to the useEffect hook and move the hideN call out of the conditional block that is only instantiating a graph value to store in the ref.

const graphRef = useRef(null);
const ref = useRef(null);

//Hide Node State
const [hideNode, sethideNode] = useState("");

const hideN = () => {
  const node = graphRef.current?.findById(hideNode);
  node.hide();
};

useEffect(() => {
  if (!graphRef.current) {
    graphRef.current = new G6.Graph(cfg);
    graphRef.current.data(data);
    graphRef.current.render();
  }
  hideN();
}, [hideNode]);
  • Related