热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

React新特性——Protals与ErrorBoundaries

为什么80%的码农都做不了架构师?Portals在React16.x新增了一个名为“Protals”的特性,直接按照字面意思翻译实在不靠谱。在描述

为什么80%的码农都做不了架构师?>>>   hot3.png

Portals

在React 16.x 新增了一个名为“Protals”的特性,直接按照字面意思翻译实在不靠谱。在描述这个特性时,我们还是用官方的英文单词来指定它。Portals的作用简单的说就是为了便于开发“弹窗”、“对话框”、“浮动卡片”、“提示窗”等脱离标准文档流的组件而设定的,用于替换之前的unstable_renderSubtreeIntoContainer。 

15.x之前的时代实现"弹窗"

过去没有这个特性的时候,我们使用React绘制“弹窗”之前无非就三种方法:

1.将弹窗作为一个子元素在组件中直接使用,然后赋予弹窗 {position: fixed ,z-index:99}这样的样式,让他漂浮在整个页面应用的最上层并相对与整个浏览器窗口定位。如果你认为fixed能实现所有要求,那么最好把下面的这个页面代码复制到本地运行看看:






Do I look fixed to you?




除此之外,这种方式处理事件的冒泡也会导致一些问题。

2.使用unstable_renderSubtreeIntoContainer方法将弹窗组件添加到body中。官方文档明确告诉你了,这玩意是有坑的,使用起来也到处是雷区。

3.最后一种方式是使用Redux来全局控制,可以在React中的模式对话框一文了解使用Redux实现对话框的内容。虽然能解决前面2个问题,但是使用 Redux 除了多引入一些包之外,这也不是一种很“自然”的实现方式。

Protals的使用

Protals组件的使用方式和普通的React组件并没有太大差异,只不过要用一个新的方法将其包裹起来:

/**
* @param child 需要展示在Protals中的组件,如

child

* @param container 组件放置的容器,就是一个Element对象。例如 document.getElementById('pop');
*/
ReactDOM.createPortal(child, container)

通常情况下,我们需要为某个组件增加子元素都会直接写在render()方法中:

render() {return (

{this.props.children}
);
}

而如果是一个 Protals 特性的组件,我们通过下面的过程创建它:

render() {return ReactDOM.createPortal(this.props.children,domNode,);
}

Protals的事件传递

Protals特性的组件渲染成真实DOM后结构上和虚拟DOM不完全一致,但是其事件流还是像普通的React组件一样可以在父组件中接收并加以处理。所以我们依然可以按照冒泡的方式处理Protals组件的事件。

看个代码的例子,我们定义两个组件——AppPop

App是整个页面的框架,负责将Pop弹窗中输入的内容显示到页面中。React 会将弹窗直接添加为的子元素。

class App extends React.Component {//constructor clickHandle() {this.setState({popShow: true})}submitHandle(value) {this.setState({message: value, popShow: false})}cancelHandle() {this.setState({popShow: false})}render() {return (

Input Message : {this.state.message}

{this.state.popShow && }
)}
}

class Pop extends React.Component {//constructorsubmitHandle() {this.props.onSubmit(this.el.value)}render() {const {onCancel} = this.propsreturn createPortal(

X

Error Boundaries

16.x 版本之前,React并没有对异常有什么处理(15.x 增加的 unstable_handleError 满地是坑),都是让使用React的开发人员按照标准Javascript的方式自行处理可能会出现的异常,这会导致某些由底层渲染过程引起的异常很难定位。此外,由于一个React组件常常伴随多个生命周期方法(lifecycle methods),如果要全面的去处理异常,会导致代码结构越来越差。

为了解决这些坑,最新版本的React提供了一个优雅处理渲染过程异常的机制—— Error Boundaries 。同时,随着 Error Boundaries 的推出,React也调整了一些异常处理的的行为和日志输出的内容。

Error Boundaries特点

特点1:通过一个生命周期方法捕获子组件的所有异常:

/**
*@param error: 被抛出的异常
*@param info: 包含异常堆栈列表的对象
**/
componentDidCatch(error, info)

特点2:只能捕获子组件的异常,而不能捕获自身出现的异常。

特点3:只能捕获渲染方法,和生命周日方法中出现的异常。而事件方法中的异常、异步代码中的异常(例如setTimeoout、一些网络请求方法)、服务端渲染时出现的异常以及componentDidCatch方法中出现的异常是无法被捕获的。如果需要捕获这些异常,只能使用Javascripttry/catch语法。

异常处理行为变更

16.x 之后的React的异常处理较之前有一些变动。当组件在使用的过程中出现某个异常没有被任何 componentDidCatch 方法捕获,那么 React 将会卸载掉整个 虚拟Dom树。这样的结果是任何未处理的异常都导致用户看到一个空白页面。官方的原文——“As of React 16, errors that were not caught by any error boundary will result in unmounting of the whole React component tree”。

这样的目的是尽可能保证页面完整性,避免由于页面的错误而导致业务逻辑错误。所以React升级到16.x版本后,至少在最顶层的根节点组件实现 componentDidCatch 方法并附加一个 错误提示的简单组件。如果根节点的组件需要处理的事物太复杂,最好多加一层包装组件仅处理异常。

有了 componentDidCatch 之后,我们可以更细粒度的按照模块或者业务来控制异常。还可以专门设定一个服务器接口来收集页面在客户端运行时出现的异常。

优化异常堆栈

新版本的React优化了异常输出,能够更清晰的跟踪到出错的位置。异常日志输出的内容将会比之前的React丰富很多,除了输出Javascript的异常信息,还会清晰的定位到错误出现的组件:

如果你的项目使用最新版本的 create-react-app 创建的,那么这一项功能已经存在了。如果没使用 Create React App,那么可以通过一个 Babel 的插件添加这个功能:

$ npm install --save-dev babel-plugin-transform-react-jsx-source

然后在对应的配置(.babelrcwebpack的plugins等)中添加:

{"plugins": ["transform-react-jsx-source"]
}

切记这项功能仅仅用于开发或测试环境,切勿用于生产环境。某些浏览器可能不支持 Function.name  的属性,可能无法正确显示组件名称(例如所有版本的IE)。可以通过使用一些 polyfill 来解决这个问题,比如这个 function-name工具 。

代码实例

最后是一个代码的例子。请按照以下步骤到github上clone下来运行。

$ git clone https://github.com/chkui/ErrorBoundariesExample.git #下载代码
$ npm install #安装node_module
$ npm start #安装完后webpakc启动

例子值得关注的就几个点。

1.通过 webpack 的方式引入了babel的源码映射插件用以定位异常出现的位置。

module: {rules: [{test: /\.js$/,use: [{loader: 'babel-loader',options: {presets: ['es2015', 'stage-0', 'react'],plugins: ['transform-react-jsx-source'], //添加插件}}],exclude: /node_modules/}]},

2.定义了四个组件——AppParentChildErrorTip,分别是入口组件、父组件、子组件和捕获到异常时用来提示的组件。

class App extends React.Component {//constructorcomponentDidCatch(error, info) {this.setState({error: true}) //处理子组件的异常}render() {return (

Example

{this.state.error ? () : ()}
)}
}

class Parent extends React.Component {//constructorclickHandle() {try {throw new Error('event error')} catch (e) {this.setState({myError: true})}}childErrorClickHandle(){this.setState({childError:true})}componentWillUpdate(nextProps, nextState) {if (nextState.myError) {throw new Error('Error')}}componentDidCatch(error, info) {this.setState({catchError: true})}render() {return (

Parent

{this.state.catchError ? ():()}
)}
}

class Child extends React.Component{//constructorcomponentWillReceiveProps(nextProps){if(nextProps.error){throw new Error('child error')}}render(){return (

Child

)}
}

Child抛出的异常会被Parent组件处理、Parent组件抛出的异常会被App组件处理,组件无法捕获自生出现的异常。

最后,由于16.x版本提供了componentDidCatch的功能,所以将15.x的unstable_handleError特性取消调了,如果需要进行升级的可以去 这里 下载并使用升级工具。


转:https://my.oschina.net/chkui/blog/1570500



推荐阅读
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • vue使用
    关键词: ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
author-avatar
手机用户2502923261
这个家伙很懒,什么也没留下!
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有