javascriptreactjsd3.jsreact-hooks

React onMouseEnter event.currentTarget is always null


I am using React d3 tree with a custom node element. I am trying to show some text on hovering a node, but it only works the first time I hover over one, then the mouse.currentTarget seems to be null each time I hover a node, so documentation.show won't be set to true. The useMemo is used so that the whole component won't rerender each time I hover over a node (because of documentation state change).

import Tree, { TreeNodeDatum } from "react-d3-tree";

const [documentation, setDocumentation] = useState({
    x: 0,
    y: 0,
    show: false,
    text: "test text.",
  });

const TreeMemo = useMemo(() => {

    const renderCustomNode = ({
      nodeDatum,
      toggleNode,
    }: {
      nodeDatum: TreeNodeDatum;
      toggleNode: () => void;
    }) => (
      <g>
        <circle
          r="15"
          onMouseEnter={(mouse) =>
            setDocumentation((prevState) => {
              return mouse.currentTarget
                ? {
                    x:
                      mouse.clientX -
                      mouse.currentTarget.getBoundingClientRect().right,
                    y:
                      mouse.clientY -
                      mouse.currentTarget.getBoundingClientRect().top,
                    show: true,
                    text: prevState.text,
                  }
                : prevState;
            })
          }
          onMouseLeave={() => {
            setDocumentation((prevState) => {
              return {
                ...prevState,
                show: false,
              };
            });
          }}
          onClick={toggleNode}
        />
        <text fill="black" strokeWidth="1" x="20">
          {nodeDatum.name}
        </text>
        {nodeDatum.attributes?.department && (
          <text fill="black" x="20" dy="20" strokeWidth="1">
            Department: {nodeDatum.attributes?.department}
          </text>
        )}
      </g>
    );
    
    return (
      <Tree
        key={triggerRecenter}
        data={orgChart}
        translate={treeTranslate}
        dimensions={
          treeContainerRef.current
            ? {
                height: treeContainerRef.current.getBoundingClientRect().height,
                width: treeContainerRef.current.getBoundingClientRect().width,
              }
            : undefined
        }
        renderCustomNodeElement={(rd3tProps) =>
          renderCustomNode({ ...rd3tProps })
        }
        orientation="vertical"
      />
    );
  }, [triggerRecenter, treeTranslate]);

Adding documentation state in useMemo deps makes it work, but triggers rerender of the whole component which is not wanted. Also using onMouseMove seems to be working, but it makes the position change.


Solution

  • Solved by changing onMouseEnter handler to below. Seems this prevents currentTarget to be null from what I understand, if I am wrong correct me.

         onMouseEnter={(event) => {
            const { clientX, clientY, currentTarget } = event;
            const { right, top } = currentTarget.getBoundingClientRect();
    
            setDocumentation((prevState) => {return {
              x: clientX - right,
              y: clientY - top,
              show: true,
              text: prevState.text,
            }});
          }}