无法读取空值的属性'style' React

4

我刚接触React,当我使用以下代码添加一个侧边栏组件时,出现了以下错误:

无法读取null对象的'style'属性

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;

下面部分是否有错误?

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

问题是什么?

如果有人能够帮忙解决,将非常感激。


你试图将JS写入JSX中吗?我认为这是不可能的。 - Monica Acha
React有一个虚拟DOM。因此,您的代码可能无法按预期工作。此外,在React中可以通过根据特定组件状态添加和删除类来轻松处理这个问题,对吧? - Prajwal
你现在使用的方式不是React的方式。你应该将样式值存储到状态中,并在元素中显示它。 - duc mai
7个回答

6

首先,在DOM完全加载之前无法访问文档元素,因此您需要添加一个检查,以确定元素是否已加载:

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>
    );
  }
}

修改后的组件将是这样的。 您应该了解一些有关ES6和类的概念。

我该如何将"w3schools.com/howto/tryit.asp?filename=tryhow_js_sidenav"中指定的HTML代码转换为React组件?我按照您建议的做了,但是侧边栏在我点击打开按钮时没有出现,我不明白为什么! - Aqib Zaman
有解决方案了吗? - Harish Soni

4

您正在尝试使用来自原始JS环境的反模式来获取DOM节点上的链接。请参阅React docs 以了解引用的用法。

由于React具有自己的DOM导航环境,因此您应该仅使用它。将您的代码更新为以下内容:

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>
    );
  }
}

我按照你的建议做了,但是侧边栏在我点击打开按钮时没有出现,我不明白为什么! - Aqib Zaman
当我按照你所说的做时,出现了错误,提示“无法读取未定义的属性'mySidenav'”,是在这个地方:this.mySidenav.current.style.width = "250px"; - Aqib Zaman

2
文档元素在DOM加载之前无法访问,因此您需要检查元素是否已加载。
    if (
  document.getElementById("mySidenav") &&
  document.getElementById("main")
) {
  document.getElementById("mySidenav").style.width = "250px";
  document.getElementById("main").style.marginLeft = "250px";
}

或者使用钩子 - useEffect()
useEffect(() => {
  document.getElementById("togBtn").style.cursor = "pointer";
   }, []);

1
当你写onclick={this.openNav()}时,你调用了一个函数而不是将它传递给属性。它在渲染阶段之前被调用,在组件挂载之前,因此你的元素不存在。要修复它,你应该传递一个函数。只需这样做:
onclick={this.openNav}
onclick={this.closeNav}

0

使用document.getElement...似乎是一种反模式 - 请参阅文档以了解refs的用法

Refs提供了一种访问在render方法中创建的DOM节点或React元素的方式。

您可能还想跟踪您的state中的宽度,这样您就可以使用setState来更新宽度,并且在JSX中具有style属性反映状态中的宽度。


我该如何将"w3schools.com/howto/tryit.asp?filename=tryhow_js_sidenav"中指定的HTML代码转换为React组件? - Aqib Zaman

0
不要直接调用方法,而是传递方法引用。
尝试将 onclick={this.openNav()} 更改为 onClick={this.openNav} 以及
onclick={this.closeNav()} 更改为 onClick={this.closeNav} 此外,你的 JSX 代码不在 render() 方法中。尝试这样做:

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>
 );
}


如何将"w3schools.com/howto/tryit.asp?filename=tryhow_js_sidenav"中指定的HTML代码转换为React组件? - Aqib Zaman

0

正如我在你的原始帖子下评论中所说,不建议以那种方式添加样式。您应该使用状态(state)代替。对于您的问题,这是绑定问题,应该像这样

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

对于您的其他元素也是如此


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接