-1

I rendered some elements with a functional component and I'm trying to select some of the elements to log them out to the console, but it logs out null. is there a special method used to select react elements?

This is my code:

let menuIcon = <i className=" bi bi-list" id="menu-icon"></i>
let cvIcon = <i className="bi bi-caret-down-fill"></i>

export default function Navbar() {
    return (
        <nav>
            <div id="menu">
                {menuIcon}

                <div id="menu-list-container">
                  <a href="#about">ABOUT</a>
                  <a href="#stack">STACK</a>
                  <a href="#contact">CONTACT</a>
                  <a href="#project">PROJECTS</a>
                </div>
            </div>

            <div id="logo">
                <span id="v">V</span>
                <span id="s">S</span>
                <span id="c">C</span>
            </div>
            
            
            <div id="cv-container">
                <button>
                    <input type="button" name="cv-btn" value="RESUME" id="cv-btn"/>
                    {cvIcon}
                </button>

                <div>
            <a href="">Download CV</a>
            <a href="">View CV</a>
               </div>

            </div>
        </nav>
    );
}

const root = document.getElementById("root");
createRoot(root).render(<Navbar></Navbar>);

const menuList = document.getElementById("menu-list-container")

console.log(menuList)
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
Vsimdy
  • 1
  • 1

1 Answers1

0

You cannot access the DOM right away after calling render; this is an asynchronous call.

A simple example involves using a basic setTimeout to wait a second after rendering.

const { useState } = React;
const { createRoot } = ReactDOM;

const menuIcon = <i className=" bi bi-list" id="menu-icon"></i>;
const cvIcon = <i className="bi bi-caret-down-fill"></i>;

const Navbar = () => {
  return (
    <nav>
      <div id="menu">
        {menuIcon}
        <div id="menu-list-container">
          <a href="#about">ABOUT</a>
          <a href="#stack">STACK</a>
          <a href="#contact">CONTACT</a>
          <a href="#project">PROJECTS</a>
        </div>
      </div>
      <div id="logo">
        <span id="v">V</span>
        <span id="s">S</span>
        <span id="c">C</span>
      </div>
      <div id="cv-container">
        <button>
          <input type="button" name="cv-btn" value="RESUME" id="cv-btn" />
          {cvIcon}
        </button>
        <div>
          <a href="">Download CV</a>
          <a href="">View CV</a>
        </div>
      </div>
    </nav>
  );
};

const root = document.getElementById("root");
createRoot(root).render(<Navbar></Navbar>);

setTimeout(() => {
  const menuList = document.getElementById("menu-list-container");
  console.log(menuList);
}, 1000);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>

Instead of a timeout, you can use a MutationObserver. This will guarantee that the element exists when it enters the DOM.

const { useState } = React;
const { createRoot } = ReactDOM;

// Adapted from: https://stackoverflow.com/a/65585776/1762224
const observe = (selector, targetNode = document.body) =>
  new Promise(res => {
    new MutationObserver(mutations =>
      res([...mutations]
        .flatMap((mutation) => [...mutation.addedNodes])
        .find((node) => node.matches && node.matches(selector))))
    .observe(targetNode, { childList: true, subtree: true });
  });

const menuIcon = <i className=" bi bi-list" id="menu-icon"></i>;
const cvIcon = <i className="bi bi-caret-down-fill"></i>;

const Navbar = () => {
  return (
    <nav className="navbar">
      <div id="menu">
        {menuIcon}
        <div id="menu-list-container">
          <a href="#about">ABOUT</a>
          <a href="#stack">STACK</a>
          <a href="#contact">CONTACT</a>
          <a href="#project">PROJECTS</a>
        </div>
      </div>
      <div id="logo">
        <span id="v">V</span>
        <span id="s">S</span>
        <span id="c">C</span>
      </div>
      <div id="cv-container">
        <button>
          <input type="button" name="cv-btn" value="RESUME" id="cv-btn" />
          {cvIcon}
        </button>
        <div>
          <a href="">Download CV</a>
          <a href="">View CV</a>
        </div>
      </div>
    </nav>
  );
};

const root = document.querySelector('#root');
createRoot(root).render(<Navbar />);

observe('nav.navbar', root)
  .then((menu) => {
    const menuList = menu.querySelector('#menu-list-container');
    console.log(menuList);
  });
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132