如何在 React.js 中管理整个身体
简介 React 是一个庞大的库,它抽象了 DOM 的所有复杂性。它使用虚拟 DOM 概念,对于大型和嵌套元素,这比直接操作 DOM 快得多。每个 React 组件都代表 DOM 中的一个节点。根据设计,组件不会直接讨论组件层次结构;您必须使用回调 props 传递数据。
但是,如果您的 React 应用想要访问某个 DOM 节点并修改它无法控制的内容,该怎么办?在本简短指南中,您将学习如何管理整个主体,包括React 中的<body>元素。
使用 ReactDOM.render() 方法
react -dom库提供特定于 DOM 的实用程序。ReactDOM.render ()方法将 React 组件渲染到指定 DOM 元素中的 DOM 中。它以 React 元素作为第一个参数,以 DOM 节点作为第二个参数。它还以可选回调作为第三个参数,该回调在组件完成渲染时执行。
ReactDOM.render(component, DOMnode [, callback]);
您可以按如下方式在主体中渲染组件:
const App = () => (
<div>
<h1>Hello World</h1>
</div>
);
ReactDOM.render(<App />, document.body);
这是一个可行的解决方案,但将组件渲染到document.body被认为是不好的做法。这是因为任何其他第三方库或浏览器扩展都可以操纵document.body及其子项,这可能会影响其中渲染的 React 组件。
您可以执行document.body.appendChild(document.createElement("div")),但这会将组件呈现在主体的直接子项内部。
操作 <body /> 元素的高阶组件
在本节中,您将了解一种更符合“React”的方式来处理<body>元素。
开发人员经常忘记他们可以在 React 组件中使用浏览器 DOM API。当 React 组件直接操作 DOM 节点时,这被视为副作用。尽管如此,它完全有效。
因此,要向<body>元素添加属性或类,您可以执行以下操作:
// to set new class
document.body.classList.add(className);
// to set attributes
document.body.setAttribute(attrName, value);
上述方法是由 DOM API 指定的,用于操作 DOM 节点,并且不是核心 React 或框架不可知的一部分。
使用上述方法,创建一个高阶组件(HOC)以在<body>元素中添加类并设置数据属性。
import React, { Component } from "react";
class ReactBody extends Component {
render() {
return props.children;
}
}
ReactBody组件将接受类和属性作为 props。以下是该组件的propTypes定义:
import PropTypes from "prop-types";
ReactBody.propTypes = {
classes: PropTypes.array,
dataAttrs: PropTypes.object,
children: PropTypes.node.isRequired
};
接下来,在componentDidMount()生命周期方法中,循环遍历每个类名和属性,并将它们添加到<body>元素中。
// ...
componentDidMount() {
if (props.classes) {
props.classes.forEach(class => {
document.body.classList.add(class);
})
}
else if (props.dataAttrs) {
Object.keys(props.dataAttrs).forEach(attr => {
document.body.setAttribute(`data-${attr}`, props.dataAttrs[attr]);
});
}
}
// ...
组件从 DOM 中卸载后,不要忘记删除属性和类名。
// ...
componentWillUnmount() {
if (props.classes) {
props.classes.forEach(class => {
document.body.classList.remove(class);
})
}
else if (props.dataAttrs) {
Object.keys(props.dataAttrs).forEach(attr => {
document.body.removeAttribute(`data-${attr}`, props.dataAttrs[attr]);
});
}
}
// ...
最后,你的高阶组件应该如下所示:
import React, { Component } from "react";
import PropTypes from "prop-types";
class ReactBody extends Component {
componentDidMount() {
if (props.classes) {
props.classes.forEach(class => {
document.body.classList.add(class);
})
}
else if (props.dataAttrs) {
Object.keys(props.dataAttrs).forEach(attr => {
document.body.setAttribute(`data-${attr}`, props.dataAttrs[attr]);
});
}
}
componentWillUnmount() {
if (props.classes) {
props.classes.forEach(class => {
document.body.classList.remove(class);
})
}
else if (props.dataAttrs) {
Object.keys(props.dataAttrs).forEach(attr => {
document.body.removeAttribute(`data-${attr}`, props.dataAttrs[attr]);
});
}
}
render() {
return this.props.children
}
}
ReactBody.propTypes = {
classes: PropTypes.array,
dataAttrs: PropTypes.object,
children: PropTypes.node.isRequired
};
export default ReactBody;
一旦准备好ReactBody HOC,您就可以将其他组件包装在<ReactBody />中,如下所示。
// ...
const Modal = props => {
<ReactBody classes={props.isOpen && ["open-modal"]}>
<div className="modal">{/* ... */}</div>
</ReactBody>;
};
结论
强烈建议您不要直接在<body>元素内渲染 React 应用,因为这可能会导致意外行为。操作<body> 的更好方法是使用 DOM 方法,如classList.add、setAttribute等。要在 React 组件之间重用这些方法,您应该创建一个 HOC 来对文档主体执行所有操作。如果您还有任何问题,请通过CodeAlphabet与我联系。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~