Reputation: 285
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()}
>
×
</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()}
>
☰ 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
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
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}">
☰ open
</span>
</div>
</div>
);
}
Upvotes: 0
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}
>
×
</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}
>
☰ open
</span>
</div>
</div>
);
}
}
Upvotes: 4
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}>
×
</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}
>
☰ open
</span>
</div>
</div>
);
}
}
The corrected component will be this. You should see some concept over ES6 and Classes.
Upvotes: 6
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
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
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