我正在尝试将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
您的假设是正确的,即您正在获得null
的结果,因为在调用render
时 DOM 尚未更新。当你需要引用原始 DOM 元素时,React 提供了一个 Ref 的概念来安全地做到这一点。你可以在 Refs 和 DOM 下的官方 React 文档中阅读有关 Refs 以及如何使用它们的信息。
在大多数情况下,React 为我们提供了比像这样手动操作 DOM 更好的选择。对于上述情况,我强烈建议使用组件状态来保存值(例如。 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;
首先,直接在 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;