# React16新特性
React更迭到了16版本,惭愧,接触前端没多久,刚用15来着,出了个react开源协议的问题,差点就弃坑了,还好react果断更到了16,采用了新的MIT开源协议,同时新增了一些特性,其实没多大改变,但是还是稍微了解一下吧。
- Error Boundary
- render方法新增返回类型
- Portals
- 支持自定义的DOM属性
- setState传入null不会触发更新
- 更好的服务器端渲染
- 新的打包策略
- ...
# Error Boundary
在以前的版本一旦组件出错,整个组件树都无法正常显示,会从根节点被unmount下来。React16针对这点,引入的Error Boundary的概念。我们可以通过Error Boundary捕获到错误并对错误做优雅处理,使用Error Boundary提供的内容替代错误组件。Error Boundary可以看做一种特殊的React组件,新增了componentDidCatch这个生命周期函数,他可以捕获自身及子树上的错误并对错误进行处理。
import React from 'react'
export default class ErrorBoundary extends Component {
constructor(props){
super(props)
this.state = { hasError: false }
}
componentDidCatch(err, info){
this.setState({hasError: true})
}
render(){
if(this.state.hasError){
return <div>Something went wrong</div>
}
return this.props.children
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
我们可以再容易出错的组件使用ErrorBoundary包裹
// 使用方法
render(){
return (
<div>
<ErrorBoundary>
<Profile user={this.state.user} />
</ErrorBoundary>
<button onClick={this.onClick}>Update</button>
</div>
)
}
2
3
4
5
6
7
8
9
10
11
# render方法新增返回类型
在React16中,render方法支持返回string,number,boolean, null,portal以及fragment(带有key属性的数组),可以再一定程度上减少DOM层级。
// string
render(){
return 'hello'
}
// number
render(){
return 123
}
// boolean
render(){
return true
}
// null
render(){
return null
}
// fragments
render(){
return [
<div key="1">hello</div>,
<div key="2">world</div>,
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 使用createPortal将组建渲染到当前组件树之外
Portals机制提供了一种直接的方式可以把一个子组件渲染到父组件渲染的DOM树之外。通过使用createPortal,我们可以将组件渲染到我们想要的任意DOM节点中,但该组件依然处在React的父组件之内。带来的一个特性就是,在子组件产生的event依然可以被React父组件捕获,但在DOM结构中,它却不是你的父组件。对于组件组织,代码切割来说,这是一个很好的属性。
import React,{Component} from 'react
import ReactDOM from 'react-dom'
export default class Overlay extends Component {
constructor(props){
super(props)
this.container = document.createElement('div')
document.body.appendChild(this.container)
}
componentWillUnmount(){
document.body.removeChild(this.container)
}
render(){
return ReactDOM.createPortal(
<div className='overlay'>
<span className='overlay-close'>×</span>
</div>,
this.container
)
}
}
.overlay{
box-sizing:border-box;
position: fixed;
top:50%;
left:50%;
width:260px;
height:200px;
margin-left:-130px;
margin-top:-100px;
padding:10px;
background-color: #fff;
outline: rgba(0,0,0,.5) solid 9999px;
}
.overlay-close{
position: absolute;
top:10px;
right:10px;
color:red;
cursor: pointer;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 支持自定义DOM属性
在之前的版本中,React会忽略无法识别的HTML和SVG属性,自定义属性只能通过data-*形式添加,现在它会把这些属性直接传递给DOM(这个改动让React去掉属性白名单,从而减少文件大小),不过有些写法依旧是无效的,如DOM传递的自定义属性是函数或event handler,依旧会被React忽略。
render(){
return (
<div a={()=>{}} onclick={this.showOverlay}></div>
)
}
2
3
4
5
# setState传入null时不会更新
当不确定是否更新时,把值设置为null可以避免更新
onChange(e){
let newValue = e.target.value
if(e.target.value === this.state.city){
newValue = null
}
this.setState({value: newValue})
}
2
3
4
5
6
7
现在setState回调会在componentDidMount/componentDidUpdate之后立刻触发,不用等到所有组件渲染完毕。
# 更好的服务器端渲染
React 16的SSR被完全重写,新的实现非常快,接近3倍性能于React 15,现在提供一种流模式streaming,可以更快地把渲染的字节发送到客户端。另外,React 16在hydrating(注:指在客户端基于服务器返回的HTML再次重新渲染)方面也表现的更好,React 16不再要求客户端的初始渲染完全和服务器返回的渲染结果一致,而是尽量重用已经存在的DOM元素。不会再有checksum(标记验证)!并对不一致发出警告。一般来说,在服务器和客户端渲染不同的内容是不建议的,但这样做在某些情况下也是有用的(比如,生成timestamp)。
# 新的打包策略
新的打包策略去掉了process.env检查。
React16的体积比上个版本见笑了32%,文件尺寸的减小一部分归功于打包方法的改变。