正文
}
}
class
BuggyCounter
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
counter
:
0
};
this
.
handleClick
=
this
.
handleClick
.
bind
(
this
);
}
componentWillMount
()
{
throw
new
Error
(
'I am crash'
);
}
handleClick
()
{
this
.
setState
(({
counter
})
=>
({
counter
:
counter
+
1
}));
}
render
()
{
if
(
this
.
state
.
counter
===
5
)
{
// Simulate a JS error
throw
new
Error
(
'I crashed!'
);
}
return
# {this.state.counter}
;
}
}
function
App
()
{
return
(
This
is
an example of error boundaries
in
React
16.
Click
on the numbers to increase the counters
.
The
counter
is
programmed to
throw
when
it reaches
5.
This
simulates a
JavaScript
error
in
a component
.
---
These
two counters are inside the same error boundary
.
If
one crashes
,
the error boundary will replace both of them
.
---
);
}
ReactDOM
.
render
(
,
document
.
getElementById
(
'root'
)
);
demo演示:
可以看到加上Error Boundary之后,除了出错的组件,其他的地方都不受影响。
而且它很清晰的告诉我们是哪个组件发生了错误。
注意事项:
Error Boundary无法捕获下面的错误:
1、事件函数里的错误
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
try {
// Do something that could throw
} catch (error) {
this.setState({ error });
}
}
render() {
if (this.state.error) {
return
# Caught an error.
}
return
Click Me
}
}
上面的例子中,handleClick方法里面发生的错误,Error Boundary是捕获不道德。因为它不发生在渲染阶段,所以采用try/catch来捕获。
2、异步代码(例如setTimeout 或 requestAnimationFrame 回调函数)
class A extends React.Component {
render() {
// 此错误无法被捕获,渲染时组件正常返回 ``
setTimeout(() => {
throw new Error('error')
}, 1000)
return (
)
}
}
3、服务端渲染
因为服务器渲染不支持Error Boundary
4、Error Boundary自身抛出来的错误 (而不是其子组件)
那这里还遗留一个问题?错误边界放在哪里。一般来说,有两个地方:
1、可以放在顶层,告诉用户有东西出错。但是我个人不建议这样,这感觉失去了错误边界的意义。因为有一个组件出错了,其他正常的也没办法正常显示了
2、包在子组件外面,保护其他应用不崩溃。
三、react portal
在介绍这个新特性之前,我们先来看看为什么需要portal。在没有portal之前,如果我们需要写一个Dialog组件,我们会这样写。
...
{ needDialog ? : null }
问题:
1、最终渲染产生的html存在于JSX产生的HTML在一起,这时候dialog 如果需要position:absolute 控制位置的话,需要保证dialog 往上没有position:relative 的干扰。
2、层级关系不清晰,dialog实际是独立在app之外的。
所以这时候Portal降临。
Portal可以帮助我们在JSX中跟普通组件一样直接使用dialog, 但是又可以让dialog内容层级不在父组件内,而是显示在独立于原来app在外的同层级组件。
如何使用:
HTML:
// 这里为我们定义Dialog想要放入的位置
JS:
// These two containers are siblings in the DOM
const appRoot = document.getElementById('app-root');
const modalRoot = document.getElementById('modal-root');
// Let's create a Modal component that is an abstraction around
// the portal API.
class