React Hooks, how to access mounted parentNode with ReactDom

Viewed 8462

I am currently migrating my react components to react hooks, but struggle with one specific case which is accessing the mounted DOM element.

My component using React.class structure :

import { Component } from "react";
import ReactDOM from "react-dom";

class LineGraph extends Component {

    componentDidMount() {
        this.element = ReactDOM.findDOMNode(this).parentNode;
    }

    render() {
        return "";
    }
}

Now using react hooks, ReactDOM.findDOMNode(this) throw the following error :

TypeError: react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.findDOMNode(...) is null

Looking at ReactDOM#findDOMNode documentation, I tried to use a references on a returned empty div but after few draw element variable become null.

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

export default function LineGraph () {

    let myRef = React.createRef();

    useEffect(() => {
        element = ReactDOM.findDOMNode(myRef.current).parentNode;
    }, []);

    return (
      <div ref={myRef}></div>
    );
}

I am looking a clean way to access the DOM element in which my react code is injected/mounted.

Just for context, my goal is to inject svg content using d3 library, my code works well with components.

2 Answers

The problem is the timing of accessing the reference.

Try using useRef hook with a listener to myRef change, and read it when it has a valid value:

import React, { useState, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';

export default function LineGraph() {
  const myRef = useRef();

  useEffect(() => {
    if (myRef.current) {
      console.log(myRef.current.parentNode)
    }
  }, [])

  return <div ref={myRef}></div>;
}

Edit react-parent-node-hooks

There are some minor issues with your code, you can make it work and simplify it at the same time.

  1. Remove the findDomNode method

It's not required as you are already accessing a node through the ref so you can use the .parentNode property directly on the referenced DOM node.

  1. Update Parent Node on each re-render

By removing the empty array from your useEffect method the component will access the parent node each time the parent Node updates. Thereby you always have access to the freshly updated parent node.

https://stackblitz.com/edit/react-qyydtt

export default function LineGraph () {
    const parentRef = React.createRef();
    let parent;

    useEffect(() => {
     parent = parentRef.current.parentNode
    });

    return (
      <div ref={parentRef}></div>
    );
}

Related