我正在尝试将DOM元素存储在React组件内的变量中。
我在组件的render()
函数中声明此变量,如下所示:
render() {
const aside = document.querySelector('aside');
...
...
}
鉴于此声明是在return
之前声明的,我猜想在声明此声明时,const aside
是null
,也许这就是为什么它不起作用的原因
我应该在哪里声明此变量?还是有更好的方法在React中存储像这样的DOM元素变量?
另一个问题:这个变量是引用浏览器DOM元素还是React的虚拟DOM元素?
这里是完整的组件:
import React, { Component } from 'react';
class Sidebar extends Component {
render() {
const aside = document.querySelector('aside');
function hideSidebar() {
aside.classList.remove('show');
}
function openSidebar() {
aside.classList.add('show');
aside.addEventListener('mouseleave', 'hideSidebar');
}
return (
<aside>
<svg onClick={openSidebar}
...
</svg>
<ul>
<li onClick={chooseSvg}>Dreamcast</li>
<li onClick={chooseSvg}>Jetson</li>
</ul>
</aside>
);
}
}
export default Sidebar;
当我单击<svg>
元素并触发onClick={openSidebar}
时,出现错误:
TypeError: Cannot read property 'classList' of null
答案 0 :(得分:2)
您的假设是正确的,因为您正在获得null
,因为在调用render
时DOM尚未更新。当您需要对原始DOM元素的引用时,React提供了Ref的概念来安全地这样做。您可以在Refs and the DOM下的官方React文档中阅读关于Ref的信息以及如何使用它们。
在大多数情况下,与像这样手动操作DOM相比,React为我们提供了更好的选择。对于上述情况,我强烈建议您使用组件状态来保存一个值(例如isSidebarOpen
)并根据该状态属性切换className
。类似于以下示例:
import React, { Component } from 'react';
class Sidebar extends Component {
constructor(props) {
super(props);
this.state = {
isSidebarOpen: false,
};
this.openSidebar = this.openSidebar.bind(this);
this.hideSidebar = this.hideSidebar.bind(this);
}
openSidebar() {
this.setState({
isSidebarOpen: true,
});
}
hideSidebar() {
this.setState({
isSidebarOpen: false,
});
}
render() {
let asideClassName = this.state.isSidebarOpen
? 'show'
: 'hide';
return (
<aside className={asideClassName} onMouseLeave={this.hideSidebar}>
<svg onClick={this.openSidebar}
...
</svg>
<ul>
<li onClick={chooseSvg}>Dreamcast</li>
<li onClick={chooseSvg}>Jetson</li>
</ul>
</aside>
);
}
}
export default Sidebar;
答案 1 :(得分:2)
首先,直接在React组件内部操作dom不是一个好主意。 除了原始答案之外,您还可以使用react挂钩-https://reactjs.org/docs/hooks-intro.html
import React, { useState } from "react";
function Sidebar() {
const [sideBarOpen, setSideBarOpen] = useState(false);
const hideSideBar = () => {
setSideBarOpen(false);
};
const showSideBar = () => {
setSideBarOpen(true);
};
const chooseSvg = () => {
//
};
return (
<aside className={sideBarOpen ? "show" : "hide"} onMouseLeave={hideSideBar}>
<svg onClick={showSideBar}>
//...
</svg>
<ul>
<li onClick={chooseSvg}>Dreamcast</li>
<li onClick={chooseSvg}>Jetson</li>
</ul>
</aside>
);
}
export default Sidebar;