当React应用程序遇到问题或出现错误时,错误边界(error boundaries)特别有用。错误边界是React组件,它会在渲染期间捕获并打印任何在树的子组件中抛出的JavaScript错误,并且,相当于错误被“停留”在边界内,防止应用程序崩溃。下面就让我们来详细讲解React中的错误边界处理以及Portals的使用。
错误边界(Error Boundaries)
React 16引入了错误边界机制(Error Boundaries),通过错误边界我们可以让React应用程序更加健康并保证应用程序中的组件不会出现错误。在React应用程序中定义错误边界很简单,只需要定义一个继承于React.Component的类,然后在render方法中判断是否发生错误即可。
定义错误边界
定义一个错误边界,通常要重写生命周期函数componentDidCatch(error, info)
,进行错误处理,并且用state保存是否出错的状态。
class AppErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
// 可以将错误信息等写入log
console.error(error, info);
this.setState({ hasError: true });
}
render() {
if (this.state.hasError) {
return <h1>发生错误了,请稍候再试!</h1>; // 自定义错误页面
}
return this.props.children;
}
}
这里我们定义了一个叫做AppErrorBoundary的错误边界组件,它会在render方法中对子组件进行包裹。如果包裹的子组件出错,则这个组件会覆盖原来子组件的位置,并显示错误提示信息。
使用错误边界
我们可以在需要进行错误边界处理的组件上套上这个错误边界组件,例如:
render() {
return (
<AppErrorBoundary>
<div className="App">
<SomeComponent /> // 这个组件可能会出错
</div>
</AppErrorBoundary>
);
}
这样,我们就可以在SomeComponent组件出现错误时,使用AppErrorBoundary的 componentDidCatch 方法,对错误进行统一的处理和展示。
Portals
Portals是React版本16与版本以上所引入的能力,功能就是让我们在组件的树形结构之外,使组件(子树)的内容在DOM树的另一个部分中渲染出来。即在当前组件之外的另一个元素上进行渲染。
创建 Portal
我们可以通过ReactDOM.createPortal方法来创建一个Portal。createPortal方法需要两个参数:
- 第一个参数:React元素,我们需要在Portal虚拟DOM中渲染一些内容,这个元素可以是任意的,例如string,Fragment,或者整个组件。
- 第二个参数:目标容器,告诉React需要把对应的输出渲染到哪个容器中。注意,这个容器是一个真实的DOM元素节点。
const modalRoot = document.getElementById('modal-root');
class Modal extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
this.el.classList.add('modal');
}
componentDidMount() {
modalRoot.appendChild(this.el);
}
componentWillUnmount() {
modalRoot.removeChild(this.el);
}
render() {
return ReactDOM.createPortal(
this.props.children, // 这里是将子组件传入,在modal的DOM节点上进行渲染
this.el,
);
}
}
注意这里的构造函数,它会创建一个元素(通过document.createElement方法),并添加一些必要的类名,这样我们就可以根据这个类名来设置Modal的样式了。componentDidMount和componentWillUnmount会生命周期方法是用来在ReactDOM渲染时维护这个模态,检查应该如何插入到DOM中并执行清除工作,而createElement方法中,我们需要将这个自己定义的div元素传递给createPortal方法作为target,之后React会将其他的内容一起渲染到这个DOM元素中。而并不是像普通的再DOM树中渲染一样。
调用 Portal
可以在其他组件中通过调用Modal组件来使用Portal。
class App extends React.Component {
constructor(props) {
super(props);
this.state = { showModal: false };
this.toggleModal = this.toggleModal.bind(this);
}
toggleModal() {
this.setState({ showModal: !this.state.showModal });
}
render() {
return (
<div>
<button onClick={this.toggleModal}>弹出对话框</button>
{this.state.showModal ? (
<Modal>
<div className="modal-dialog">
<h1>这个是对话框的标题</h1>
<div>这里是对话框的内容</div>
<button onClick={this.toggleModal}>关闭</button>
</div>
</Modal>
) : null}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
在这个例子中,我们可以看到当用户点击App组件中的“弹出对话框”按钮时,应用程序会将一个Modal组件添加到DOM树中,而这个Modal组件使用了Portal来确保它渲染到modal-root元素中。
这也就是React中Portals的使用。我们使用createPortal方法实现了在组件的树形结构之外去渲染内容,并且能够不受组件状态的限制去渲染内容。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:React中Portals与错误边界处理实现 - Python技术站