Aqib Zaman
Aqib Zaman

Reputation: 285

Cannot read property 'style' of null React

I am new to react when I add a component for side bar with the following code I got the error:

Cannot read property 'style' of null

import React, { Component } from "react";
import "../css/sidebar.css";

class Sidebar extends Component {
  state = {};

  openNav() {
    document.getElementById("mySidenav").style.width = "250px";
    document.getElementById("main").style.marginLeft = "250px";
  }

  closeNav() {
    document.getElementById("mySidenav").style.width = "0";
    document.getElementById("main").style.marginLeft = "0";
  }

  render() {
    return (
      <div>
        <div id="mySidenav" class="sidenav">
          <a
            href="javascript:void(0)"
            class="closebtn"
            onclick={this.closeNav()}
          >
            &times;
          </a>
          <a href="#">About</a>
          <a href="#">Services</a>
          <a href="#">Clients</a>
          <a href="#">Contact</a>
        </div>

        <div id="main">
          <h2>Sidenav Push Example</h2>
          <p>
            Click on the element below to open the side navigation menu, and
            push this content to the right.
          </p>
          <span
            styles={{ fontSize: "30", cursor: "pointer" }}
            onclick={this.openNav()}
          >
            &#9776; open
          </span>
        </div>
      </div>
    );
  }
}

export default Sidebar;

Is the error in the part below?

document.getElementById("mySidenav").style.width = "0";

What is the problem?

If any one can help it will very much appreciable.

Upvotes: 5

Views: 20191

Answers (7)

SouMitya chauhan
SouMitya chauhan

Reputation: 331

document element cannot be accessed until your DOM is loaded so you need to check if the element has been loaded or not

    if (
  document.getElementById("mySidenav") &&
  document.getElementById("main")
) {
  document.getElementById("mySidenav").style.width = "250px";
  document.getElementById("main").style.marginLeft = "250px";
}

or use hook - useEffect()

useEffect(() => {
  document.getElementById("togBtn").style.cursor = "pointer";
   }, []);

Upvotes: 2

Sajib Khan
Sajib Khan

Reputation: 24204

Don't invoke the method directly, instead pass the method reference.

Try changing onclick={this.openNav()} to onClick={this.openNav}

and

onclick={this.closeNav()} to onClick={this.closeNav}

Also your JSX code is not right inside render() method. Try this:

render() {
  return (

  <div>
    <div id="mySidenav" className="sidenav">
      <a href="javascript:void(0)" className="closebtn" onClick="{this.closeNav}">
        ×
      </a>
      <a href="#">About</a>
      <a href="#">Services</a>
      <a href="#">Clients</a>
      <a href="#">Contact</a>
    </div>
    <div id="main">
      <h2>Sidenav Push Example</h2>
      <p>
        Click on the element below to open the side navigation menu, and
        push this content to the right.
      </p>
      <span style={{ fontsize: '30', cursor: 'pointer' }} onClick="{this.openNav}">
        &#9776; open
      </span>
    </div>
  </div>
 );
}

Upvotes: 0

Sviat Kuzhelev
Sviat Kuzhelev

Reputation: 1788

You are trying to use an anti-pattern from vanilla JS environment to get the link on DOM Node. See React docs for usage of refs.

Since React has own DOM navigation environment, you should use only it. Update your code like the following:

import React, { Component } from "react";
import "../css/sidebar.css";

class Sidebar extends Component {
  constructor(props){
      super(props)

      this.state = {}

      this.mySidenav = React.createRef()
      this.main = React.createRef()
  }

  openNav() {
    this.mySidenav.current.style.width = "250px";
    this.main.current.style.marginLeft = "250px";
  }

  closeNav() {
    this.mySidenav.current.style.width = "0";
    this.main.current.style.marginLeft = "0";
  }

  render() {
    return (
      <div>
        <div id="mySidenav" ref={this.mySidenav} class="sidenav">
          <a
            href="javascript:void(0)"
            class="closebtn"
            onclick={this.closeNav}
          >
            &times;
          </a>
          <a href="#">About</a>
          <a href="#">Services</a>
          <a href="#">Clients</a>
          <a href="#">Contact</a>
        </div>

        <div id="main" ref={this.main}>
          <h2>Sidenav Push Example</h2>
          <p>
            Click on the element below to open the side navigation menu, and push this content to the right.
          </p>
          <span
            styles={{ fontSize: "30", cursor: "pointer" }}
            onclick={this.openNav}
          >
            &#9776; open
          </span>
        </div>
      </div>
    );
  }
}

Upvotes: 4

Harish Soni
Harish Soni

Reputation: 1896

First of all the document element cannot be accessed until your DOM is fully loaded so you need to add a check if the element has been loaded or not:

class Sidebar extends React.Component {
  state = {};

  //Here you are not binding your methods nor you are using the ES6 Arrow function so you need to change the code here also.
  openNav = () => {
    if (
      document.getElementById("mySidenav") &&
      document.getElementById("main")
    ) {
      document.getElementById("mySidenav").style.width = "250px";
      document.getElementById("main").style.marginLeft = "250px";
    }
  };

  closeNav = () => {
    if (
      document.getElementById("mySidenav") &&
      document.getElementById("main")
    ) {
      document.getElementById("mySidenav").style.width = "0";
      document.getElementById("main").style.marginLeft = "0";
    }
  };

  render() {
    return (
      <div>
        <div id="mySidenav" class="sidenav">
           //Here you are calling the function on initial render that is why you are getting the error. you need to pass the function like this in order to trigger it on an event.
          <a href="javascript:void(0)" class="closebtn" onclick={this.closeNav}>
            &times;
          </a>
          <a href="#">About</a>
          <a href="#">Services</a>
          <a href="#">Clients</a>
          <a href="#">Contact</a>
        </div>

        <div id="main">
          <h2>Sidenav Push Example</h2>
          <p>
            Click on the element below to open the side navigation menu, and
            push this content to the right.
          </p>
          <span
            styles={{ fontSize: "30", cursor: "pointer" }}
            //Same as above here also
            onclick={this.openNav}
          >
            &#9776; open
          </span>
        </div>
      </div>
    );
  }
}

The corrected component will be this. You should see some concept over ES6 and Classes.

Upvotes: 6

duc mai
duc mai

Reputation: 1422

as my comment under your original post, you are not recommended to add styles that way. you should use state instead. For your question, it was your binding problem it should like this

 <a href="javascript:void(0)"
    class="closebtn"
    onclick={this.closeNav}
 >

and the same goes for your other element

Upvotes: 0

Mikhail Litvinov
Mikhail Litvinov

Reputation: 452

When you write onclick={this.openNav()} you CALL a function instead of passing it to the prop. It calls in the render phase, before component mounting, so your elements do not exist. To fix it, you should pass a function instead. Simply do:

onclick={this.openNav}
onclick={this.closeNav}

Upvotes: 1

Francis Leigh
Francis Leigh

Reputation: 1960

using document.getElement... seems an anti-pattern - see docs for usage of refs

Refs provide a way to access DOM nodes or React elements created in the render method.

You may also want to keep track of widths within your state that way you can use setState to update the widths and have style properties within your JSX reflect those widths in the state.

Upvotes: 0

Related Questions