React js cannot read property of null 'style' in javascript

the javascript code:

function openNav() {
        document.getElementById("mySidenav").style.width = "250px";
      }
      
      function closeNav() {
        document.getElementById("mySidenav").style.width = "0";
      }

its a react project its mostly giving this error and other javascript errors.please help!!!

It likely means that document.getElementById("mySidenav") is returning null and not the element.

But we need to see way more code than what you have posted to really be able to help. Do you have a GitHub with the code or some live version we can look at?

no ı dont have a github but ı can post it on here this is my header component

import React from 'react'
import "./Header.css"
import { BrowserRouter as Router, Switch, Route, Link} from "react-router-dom";
import ReactDOM from "react-dom"

function Header() {
    
    function openNav() {
        document.getElementById("mySidenav").style.width = "250px";
      }
      
      function closeNav() {
        document.getElementById("mySidenav").style.width = "0";
      }
    return (
        <nav className="Header">
            <img className="logo" src="./assets/logo.png" alt=""/>
            <div id="mySidenav" class="sidenav">
            <a href="javascript:void(0)" className="closebtn" onClick={closeNav()}>&times;</a>
            <a href="#">About</a>
            <a href="#">Services</a>
            <a href="#">Clients</a>
            <a href="#">Contact</a>
            </div>
        </nav>
    )
}

export default Header

You are running () the closeNav function on first load, onClick={closeNav()}. Try just passing the function onClick={closeNav}.

1 Like

Edit: I have left the answer below but the other answers do the job with just a simple change, so you may not want to look at this, unless you are interested in exploring other approaches.

You can only play with the DOM - i.e. document.getElementById("mySidenav") - once those elements exist. And that is sometime after the render has occurred in React, as it needs to run the Render than figure out how to update the DOM, your code is run too early in the cycle.

There are at 2 solutions I can think of:

One is to use state to manage whether the nav is open or not, and then based on that state render:


function App() {
    
  const [navOpen, setNavOpen] = useState(true)

  function openNav() {
    setNavOpen(true);
  }
    
  function closeNav() {
    setNavOpen(false);
  }

  return (
      <nav className="Header">
          <img className="logo" src="./assets/logo.png" alt=""/>
          <div id="mySidenav" class="sidenav" style={{width: navOpen ? 250 : 0}}>
          <a href="javascript:void(0)" className="closebtn" onClick={() => closeNav()}>&times;</a>
          <a href="#">About</a>
          <a href="#">Services</a>
          <a href="#">Clients</a>
          <a href="#">Contact</a>
          </div>
      </nav>
  )
}

The other, which is closer to your approach is to use refs to get a reference to the DOM element. Something like this:

function App() {
    
  const divRef = useRef()

  function openNav() {
    divRef.current.style.width = 250;
  }
    
  function closeNav() {
    divRef.current.style.width = 0;
  }

  return (
      <nav className="Header">
          <img className="logo" src="./assets/logo.png" alt=""/>
          <div id="mySidenav" class="sidenav" ref={divRef}>
          <a href="javascript:void(0)" className="closebtn" onClick={() => closeNav()}>&times;</a>
          <a href="#">About</a>
          <a href="#">Services</a>
          <a href="#">Clients</a>
          <a href="#">Contact</a>
          </div>
      </nav>
  )
}

See https://reactjs.org/docs/refs-and-the-dom.html for more details.

I think what @lasjorg said is exactly the problem. In React (JavaScript), you only need to pass a pointer to function you want called upon an event. Except have done this: onClick={ e => closeNav(e) }

Most of the point of React is to remove the need to do this. JSX is not HTML, it’s a syntax that lets you write functions that look like HTML (and those functions, when processed by the ReactDOM library, result in HTML that looks like the JSX).

To access that HTML using DOM methods you can jump through hoops like you’re trying to do. The second solution from @martinc shows we how to do this, but this is not a good reason to use refs, it complicates the code for no good reason (you’re deliberately fighting with React). It’s very unlikely that at this point you need to get into using refs at all: you can just adjust the style directly (as shown in the first solution), and tbh that’s how you should be writing this logic.

@DanCouper I totally agree, it is not the React way of doing things. I just wanted to point out what the problem was.

I would very much suggest that @oguzhanefe32 looks into the different ways of styling React components. There are not only better ways but much more powerful ways of styling components that let you use logic and component state for the styling.

1 Like

Yes the problem with answering these sorts of questions is that there are multiple answers depending on what level you are aiming at.

At one level there is the quick fix : Use the arrow function to delay execution of the call until the event happens. It works! Job done!

But the OP will now get pain later when / if that element is shown/hidden based on state or props and the thing may or may not exist, or gets rendered again after the click or whatever.

So then it’s good to teach the best way, but you then have to go into why. I think your sentence “Most of the point of React is to remove the need to do this.” gets to the core of this, it’s sort of what I wanted to say.

I wonder why FCC has left someone thinking like this, I imagine it’s because you learn DOM manipulation first, you have your hammer that works nicely, then you learn React, and you are not told to put down the hammer as you are now using screws. You can hammer a screw in and it will work, but you might get problems later!

1 Like

I would like to just make it clear that wrapping the handler inside an anonymous function is not required unless you need to pass some arguments other than the event to the handler. If all you need is the event, you do not need to wrap the handler.

export default function App() {

  const handleClick = (event) => {
    console.log(event); // SyntheticBaseEvent
    console.log(event.target); // <button>Click me!</button>
  }
  return (
    <div className="App">
      <button onClick={handleClick}>Click me!</button>
    </div>
  );
}
1 Like