Search code examples
reactjsdomheight

can not access or manipulate the dom using references in react


I tried to access the dom to get the height of a specific element in react using useRef() hook, and assign the height of another element to it, so its height would change dynamically based on the height change of the reference element and I used the height.current.clientHeight property but I encountered an error message saying:

TypeError: Cannot read properties of null (reading 'clientHeight')

and here is the code:

import React from "react";
import Link from "next/link";
import MenuIcon from "./MenuIcon";
import { useState } from "react";
import Image from "next/image";
import bg from "../public/bg.jpg";
import { useRef } from "react";

const Navbar = () => {
  const height = useRef(null);
  const [open, setOpen] = useState(false);
  function handleClick() {
    setOpen(!open);
  }
  return (
    <>
      <MenuIcon bgC="bg-white" handle={handleClick} open={open} />
      <div className="w-full relative h-[40%]" ref={height}>
        <nav className="xs:max-md:hidden flex z-20 justify-between md:max-lg:justify-end md:max-lg:gap-24 text-white bg-transparent backdrop-blur-lg  py-3 px-6 ">
          <div className="hover:text-gray-300 hover:text-[20px] ease-in duration-100">
            <Link href="/">About me</Link>
          </div>
          <div className="hover:text-gray-300 hover:text-[20px] ease-in duration-100">
            <Link href="/">My skills</Link>
          </div>
          <div className="hover:text-gray-300 hover:text-[20px] ease-in duration-100">
            <Link href="/">Portfolio</Link>
          </div>
          <div className="hover:text-gray-300 hover:text-[20px] ease-in duration-100">
            <Link href="/">Contacts</Link>
          </div>
        </nav>

        <Image
          src={bg}
          layout="responsive"
          objectFit="contain"
          width={400}
          height={400}
          alt="/"
        />

        <div className="w-full h-full bg-black/40 absolute top-0 lef-0 right-0">
          <h1 className="text-white w-[75%] font-Neo font-[12px] box-border text-2xl mx-auto text-center translate-y-[140px]">
            Hi there! My name is Alharith and I am a front-end developer.
          </h1>
        </div>
      </div>
      <div
        className={
          open
            ? `w-auto h-${height.current.clientHeight} box-border px-12 bg-blue-400 backdrop-blur-sm fixed top-0 right-0 translate-x-0 duration-300 ease-in flex flex-col items-center justify-around text-2xl`
            : `w-auto h-${height.current.clientHeight} px-12 py-[30px] bg-transparent backdrop-blur-sm fixed top-0 right-0 translate-x-[100%] duration-300 ease-in flex flex-col items-center justify-around text-2xl`
        }
      >
        <div className="w-full flex flex-col justify-around items-center h-[50%] gap-8 text-2xl font-Neo">
          <div className="font-Neo text-2xl hover:text-[20px] hover:text-gray-100 duration-100 ease-in">
            <Link href="/">About me</Link>
          </div>
          <div className="font-Neo text-2xl hover:text-[20px] hover:text-gray-100 duration-100 ease-in">
            <Link href="/">My Skills</Link>
          </div>
          <div className="font-Neo text-2xl hover:text-[20px] hover:text-gray-100 duration-100 ease-in">
            <Link href="/">Portfolio</Link>
          </div>
          <div className="font-Neo text-2xl hover:text-[20px] hover:text-gray-100 duration-100 ease-in">
            <Link href="/">Contacts</Link>
          </div>
        </div>
      </div>
    </>
  );
};

export default Navbar;

I tried checking if the "height.current !== null" and if true would assign the value of the clientHeight to another variable, if not would assign "auto" as so:

const hi = height.current ? ${height.current.clientHeight} : "auto"

still getting the same error

I expected it to work fine but it really didn't


Solution

  • The useRef hook variable doesn't get the current property immediately. This gets populated after the initial DOM render.

    To get this working, add a useEffect hook with height.current in dependency array.

    And use a flag with useState hook and inside useEffect hook, update the flag.

     const [flag, setFlag] = useState(false);
     useEffect(() => {
        if(height.current) setFlag(true);
     }, [height.current]);
    
     // and use the flag in div class
     <div 
        className={ open && flag ? `w-auto h-${height.current.clientHeight}...` }
     >
     //
     </div>
      
    

    For more info, refer this answer