前段时间React的16版本发布了,采用了MIT开源许可证,新增了一些新的特性。

  1. Error Boundary
  2. render方法新增返回类型
  3. Portals
  4. 支持自定义DOM属性
  5. setState传入null时不会再触发更新
  6. 更好的服务器端渲染
  7. 新的打包策略
  8. ...

1. 使用Error Boundary处理错误组件

之前,一旦某个组件发生错误,整个组件树将会从根节点被unmount下来。React 16修复了这一点,引入了Error Boundary的概念,中文译为“错误边界”,当某个组件发生错误时,我们可以通过Error Boundary捕获到错误并对错误做优雅处理,如使用Error Boundary提供的内容替代错误组件。Error Boundary可以看作是一种特殊的React组件,新增了componentDidCatch这个生命周期函数,它可以捕获自身及子树上的错误并对错误做优雅处理,包括上报错误日志、展示出错提示,而不是卸载整个组件树。(注:它并不能捕获runtime所有的错误,比如组件回调事件里的错误,可以把它想象成传统的try-catch语句)

//最佳实践:将ErrorBoundary抽象为一个公用的组件类

import React, { Component } from 'react'

export default class ErrorBoundary extends Component {
  constructor(props) {
    super(props)
    this.state = { hasError: false }
  }
  componentDidCatch(err, info) {
    this.setState({ hasError: true })
    //sendErrorReport(err,info)
  }
  render(){
    if(this.state.hasError){
      return <div>Something went wrong!</div>
    }
    return this.props.children
  }
}

我们可以在容易出错的组件外使用ErrorBoundary将它包裹起来,如下

//使用方式
render(){
  return (
    <div>
      <ErrorBoundary>
        <Profile user={this.state.user} />
      </ErrorBoundary>
      <button onClick={this.onClick}>Update</button>
    </div>
  )
}

如果Profile组件发生错误,将会使用ErrorBoundary提供的<div>Something went wrong</div>代替它,而不会引起整个组件树的卸载。

2. render方法新增返回类型

在React 16中,render方法支持直接返回string,number,boolean,null,portal,以及fragments(带有key属性的数组),这可以在一定程度上减少页面的DOM层级。

//string
render(){
  return 'hello,world'
}

//number
render(){
  return 12345
}

//boolean
render(){
  return isTrue?true:false
}

//null
render(){
  return null
}

//fragments,未加key标识符,控制台会出现warning
render(){
  return [
    <div>hello</div>,
    <span>world</span>,
    <p>oh</p>
  ]
}

以上各种类型现在均可以直接在render中返回,不需要再在外层包裹一层容器元素,不过在返回的数组类型中,需要在每个元素上加一个唯一且不变的key值,否则控制台会报一个warning。

3.使用createPortal将组件渲染到当前组件树之外

Portals机制提供了一种最直接的方式可以把一个子组件渲染到父组件渲染的DOM树之外。默认情况下,React组件树和DOM树是完全对应的,因此对于一些Modal,Overlay之类的组件,通常是将它们放在顶层,但逻辑上它们可能只是属于某个子组件,不利于组件的代码组织。通过使用createPortal,我们可以将组件渲染到我们想要的任意DOM节点中,但该组件依然处在React的父组件之内。带来的一个特性就是,在子组件产生的event依然可以被React父组件捕获,但在DOM结构中,它却不是你的父组件。对于组件组织,代码切割来说,这是一个很好的属性。

//实现一个简易蒙层效果,抽象出一个通用的Overlay组件
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' onClick={this.props.onClose}>&times;</span>
        {this.props.children}
      </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;
}

使用方式如下:

class App extends Component {
 constructor(props) {
  super(props);
  this.state = {
   overlayActive: false
  }
  this.closeOverlay = this.closeOverlay.bind(this);
  this.showOverlay = this.showOverlay.bind(this);
 }
 closeOverlay() {
  this.setState({ overlayActive: false })
 }
 showOverlay() {
  this.setState({ overlayActive: true })
 }
 render() {
  return (
   <div className="App">
    <div>hello world!</div>
    {this.state.overlayActive &&
     <Overlay onClose={this.closeOverlay}>overlay content</Overlay>}
    <button onClick={this.showOverlay}>show</button>
   </div>
  );
 }
}

效果如图:


4.支持自定义DOM属性

在之前的版本中,React会忽略无法识别的HTML和SVG属性,自定义属性只能通过data-*形式添加,现在它会把这些属性直接传递给DOM(这个改动让React可以去掉属性白名单,从而减少了文件大小),不过有些写法仍然是无效的。如DOM传递的自定义属性是函数类型或event handler时,依然会被React忽略。

//错误写法
render(){
  return(
    <div a={()=>{}} onclick={this.showOverlay}></div>
  )
)
//Warning: Invalid event handler property `onclick`. Did you mean `onClick`?
//Warning: Invalid value for prop `a` on <div> tag. Either remove it from the element, or pass a string or number value to keep it in the DOM.

现在class和tabindex等属性可以被传递给DOM,但依然会报一个Warning,建议使用标准的驼峰式className,tabIndex等。

5.setState传入null时不会再触发更新

比如在一个选择城市的函数中,当点击某个城市时,newValue的值可能发生改变,也可能是点击了原来的城市,值没有变化,返回null则可以直接避免触发更新,不会引起重复渲染,不需要在shouldComponentUpdate函数里面去判断。

selectCity(e){
  const newValue = e.target.value;
  this.setState((state)=>{
    if(state.city===newValue){
      return null;
    }
    return {city:newValue}
  })
)

注意:现在setState回调(第二个参数)会在componentDidMount/componentDidUpdate后立即触发,而不是等到所有组件渲染完成之后。

6.更好的服务器端渲染

React 16的SSR被完全重写,新的实现非常快,接近3倍性能于React 15,现在提供一种流模式streaming,可以更快地把渲染的字节发送到客户端。另外,React 16在hydrating(注:指在客户端基于服务器返回的HTML再次重新渲染)方面也表现的更好,React 16不再要求客户端的初始渲染完全和服务器返回的渲染结果一致,而是尽量重用已经存在的DOM元素。不会再有checksum(标记验证)!并对不一致发出警告。一般来说,在服务器和客户端渲染不同的内容是不建议的,但这样做在某些情况下也是有用的(比如,生成timestamp)。

7.新的打包策略

新的打包策略中去掉了process.env检查。

React 16的体积比上个版本减小了32%(30% post-gzip),文件尺寸的减小一部分要归功于打包方法的改变。

react is 5.3 kb (2.2 kb gzipped), down from 20.7 kb (6.9 kb gzipped).
react-dom is 103.7 kb (32.6 kb gzipped), down from 141 kb (42.9 kb gzipped).
react   react-dom is 109 kb (34.8 kb gzipped), down from 161.7 kb (49.8 kb gzipped).

写在最后,React 16采用了新的核心架构React Fiber。官方解释是“React Fiber是对核心算法的一次重新实现”,后续再深入学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

十分钟带你快速了解React16新特性的更多相关文章

  1. Webpack3+React16代码分割的实现

    这篇文章主要介绍了Webpack3+React16代码分割的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. 十分钟带你快速了解React16新特性

    这篇文章主要介绍了十分钟带你快速了解React16新特性,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部