学习React系列(七)——Fragments、Portals、Error Boundaries与WEB组件
Error Boundaries
React.Fragment
想象一个场景,想把td包装为组件添加到table中去,代码如下:
- class MyTable extends React.PureComponent {
- render() {
rejturn(- <table>
<tbody- <tr>
- <MyTd></MyTd>
- </tr>
- </table>
</tbody>
)- }
- }
- class MyTd extends React.PureComponent {
- render() {
- return(
- <React.Fragment>
- <td>a</td><td>a</td>
- </React.Fragment>
- )
- }
- }
自定义的MyTable中插入自定义的MyTd.....,对不起直接报错,tr的子元素只能为td而实际上中间还套了一层div。。。。。
为了解决如上问题React.Fragment横空出世
- class MyTd extends React.PureComponent {
- render() {
- return(
- <React.Fragment key={1}>
- <td>a</td><td>a</td>
- </React.Fragment>
- )
- }
- }
补充一下,React.Fragment暂时只支持key这一个属性,还有它可以写成<></>这样的形式,当然它也可以用来减少dom结构的嵌套,如果你不想用二外的div来包裹内容,那么可以使用改组件,其和原生的DocumentFragment相似。
- render() {
- return (
- <>
- <ChildA />
- <ChildB />
- <ChildC />
- </>
- );
- }
portals
想象两个个场景:一、点击父组件中的一个按钮,弹出个弹框,弹框面积要求大于父组件。
场景一解决方案就是将弹窗挂到其他的Dom上面
- class Mask extends React.PureComponent {
- render() {
- return (
//这里我很想知道为什么如果不加top,那么弹窗默认加到最初的div下面- <div style={{position: "absolute",top:"0", width: '400px', height: '400px', border: '1px solid red',pointerEvents:"none" }}></div>
- )
- }
- }
- class Parent extends React.PureComponent {
- constructor(props) {
- super(props)
- this.state = {
- show: false
- }
- this.show = this.show.bind(this)
- }
- show() {
- let show = !this.state.show
- this.setState({
- show
- })
- }
- render() {
- return (
- <div style={{ width: '100px', height: '100px', border: '1px solid black' }}>
- <button onClick={this.show}>展示弹窗</button>
- {this.state.show && ReactDOM.createPortal(<Mask />, document.getElementById('root'))}
- </div>
- )
- }
- }
结论:对于 portal 的一个典型用例是当父组件有 overflow: hidden
或 z-index
样式,但你需要子组件能够在视觉上“跳出(break out)”其容器。例如,对话框、hovercards以及提示框。
二、组件a与b同级,要求组件b可以捕获a中的某个事件
- //index.html中的代码
- <html>
- <body>
- <div id="app-root"></div>
- <div id="modal-root"></div>
- </body>
- </html>
- //reactjs
- const appRoot = document.getElementById('app-root');
- const modalRoot = document.getElementById('modal-root');
- class Modal extends React.Component {
- constructor(props) {
- super(props);
- this.el = document.createElement('div');
- }
- componentDidMount() {
- modalRoot.appendChild(this.el);
- }
- componentWillUnmount() {
- modalRoot.removeChild(this.el);
- }
- render() {
- return ReactDOM.createPortal(
// this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。- this.props.children,
- this.el,
- );
- }
- }
- class Parent extends React.Component {
- constructor(props) {
- super(props);
- this.state = {clicks: 0};
- this.handleClick = this.handleClick.bind(this);
- }
- handleClick() {
- // This will fire when the button in Child is clicked,
- // updating Parent's state, even though button
- // is not direct descendant in the DOM.
- this.setState(prevState => ({
- clicks: prevState.clicks + 1
- }));
- }
- render() {
- return (
- <div onClick={this.handleClick}>
- <p>Number of clicks: {this.state.clicks}</p>
- <p>
- Open up the browser DevTools
- to observe that the button
- is not a child of the div
- with the onClick handler.
- </p>
- <Modal>
- <Child />
- </Modal>
- </div>
- );
- }
- }
- function Child() {
- // The click event on this button will bubble up to parent,
- // because there is no 'onClick' attribute defined
- return (
- <div className="modal">
- <button>Click</button>
- </div>
- );
- }
- ReactDOM.render(<Parent />, appRoot);
尽管 portal 可以被放置在 DOM 树的任何地方,但在其他方面其行为和普通的 React 子节点行为一致。包含事件冒泡。一个从 portal 内部会触发的事件会一直冒泡至包含 React 树 的祖先。由于 portal 存在于 React 树中,而不用考虑其在 DOM 树中的位置。
Error Boundaries
解决的问题:部分 UI 的异常不应该破坏了整个应用
不适用的场景:
- 事件处理 (了解更多)(使用try/catch)
- 异步代码 (例如
setTimeout
或requestAnimationFrame
回调函数) - 服务端渲染
- 错误边界自身抛出来的错误 (而不是其子组件)
为什么不用try/catch
try/catch 用于命令式而react组件是声明式的(jsx无法识别)声明什么需要被渲染
在react16+版本中如果使用错误边界,若错误边界中的组件出现错误,只要能被捕获,那么应用不会整体崩溃,否则,应用将整体unmount。
用开发模式的时候错误边界中组件出错会有警告提示如下:
点击右上角的X之后回到页面仍会看到组件,代表组件并没有崩溃
遗留问题:不知道在生成模式中还会不会弹出这个错误提示,个人觉得不应该存在,否则太影响体验了,我也不知道如何运行生产模式的react,希望知道的可以留言
WEB组件
定义:通过一种标准化的非侵入的方式封装一个组件,每个组件能组织好它自身的 HTML 结构、CSS 样式、JavaScript 代码,并且不会干扰页面上的其他代码
下面来看一个例子,该页面名字为favorite-color.html:
- <!-- WebComponent example based off element-boilerplate: https://github.com/webcomponents/element-boilerplate -->
- <template>
- <style>
- .coloured {
- color: red;
- }
- </style>
- <p>My favorite colour is: <strong class="coloured">Red</strong></p>
- </template>
- <script>
- (function() {
- // Creates an object based in the HTML Element prototype
- var element = Object.create(HTMLElement.prototype);
- // Gets content from <template>
- var template = document.currentScript.ownerDocument.querySelector('template').content;
- // Fires when an instance of the element is created
- element.createdCallback = function() {
- // Creates the shadow root
- var shadowRoot = this.createShadowRoot();
- // Adds a template clone into shadow root
- var clone = document.importNode(template, true);
- shadowRoot.appendChild(clone);
- };
- document.registerElement('favorite-colour', {
- prototype: element
- });
- }());
- </script>
在另一个html页面中引入上面的组件:
- <!DOCTYPE html>
- <html>
- <head lang="en">
- <meta charset="UTF-8">
- <title>My First WebComponent</title>
- <link rel="import" href="components/favorite-colour.html" />
- </head>
- <body>
- <favorite-colour></favorite-colour>
- </body>
- </html>
目前已经有三个基于 WebComponent 标准的框架:X-Tag, Polymer, Bosonic
注意:若你正在使用第三方Web组件,其最好的解决方案是编写一个 React组件,以包装该 Web组件。由Web组件触发的事件可能无法通过React渲染树来正确冒泡。
你需要手动捕获事件处理器以处理那些在React组件里的事件。
参考:https://reactjs.org/docs/fragments.html
https://doc.react-china.org/docs/error-boundaries.html
http://blog.csdn.net/meikidd/article/details/44628915
学习React系列(七)——Fragments、Portals、Error Boundaries与WEB组件的更多相关文章
- 7.oracle学习门户系列七---网络管理和配置
oracle学习门户系列七 网络管理和配置 们学习了模式和用户.包含模式定义以及模式的作用. 这篇我么来看下ORACLE数据库中的网络管理和配置.只是这篇好像和上篇没有继承啊.这怎么看? Ok,事实上 ...
- 学习React系列(四)——受控组件与非受控组件
受控组件:通过组件的状态与属性的改变来控制组件 不可控组件:直接通过底层的dom来控制组件(具体来说就是通过绑定再底层dom上的方法来实现的,比如说ref,onChange) 受控组件 functio ...
- 学习React系列(十)——Render Props
解决问题:将行为封装,供多个组件使用(在多个组件之间分享某段代码) 组件中的props属性中包含一个"render"属性(该属性为一个返回值为元素的方法),然后在该组件的rende ...
- 学习React系列(九)——高阶函数
定义:高阶组件就是一个函数,且该函数接收一个组件作为参数,并返回一个新的组件. (上一篇已经说过了高阶组件可以用来解决交叉问题) 一.不要改变原始组件,使用组合 class A extends Rea ...
- 学习react系列(八)—— mixins迁移
先来介绍一下mixins(混入) 先来看一段代码: const mixin = function(obj, mixins) { const newObj = obj; newObj.prototype ...
- 学习React系列(六)——更新dom细节于原理
React更新dom的依据: 1.不同类型的elements会产生不同的树 2.通过render方法中包含key属性的子元素,开发者可以示意哪些子元素可能是稳定的. 更新过程: 一.根元素类型不同:旧 ...
- 学习React系列(五)——使性能最优
提高性能可分为两方面: 一.配置层面 二.代码层面 本文只从代码层面考虑: 一.避免重复渲染 这里要说一句: 当shouldComponentUpdate返回false的时候不触发render函数也就 ...
- 学习React系列(三)——Refs和Dom
一.适用于以下场景: 1.控制焦点,文本选择,或者媒体控制 2.触发必要的动画 3.整合第三方dom库 二.不要过度使用ref 如果想通过ref来改变state,那么换一种方式-变量提升可能会更好. ...
- 学习React系列(二)——深入了解JSX
1.JX实际上是React.createElement(component,props,...children)的语法糖 2.JSX判断是否为react组件的依据是标签首字母为大写(所以要求用户自定义 ...
随机推荐
- 使用了旧版nuget的.net项目在git中的问题
曾几何时,使用nuget包管理项目依赖还需要将nuget执行程序及其配置文件包含在项目中. 如上图所示,在解决方案文件夹中,有专门为nuget程序设置的 .nuget 子目录. 当将项目纳入git管理 ...
- 用Canvas写一个简单的游戏--别踩白块儿
第一次写博客也不知怎么写,反正就按照我自己的想法来吧!怎么说呢?还是不要扯那些多余的话了,直接上正题吧! 第一次用canvas写游戏,所以挑个简单实现点的来干:别踩白块儿,其他那些怎么操作的那些就不用 ...
- UITableViewStyleGrouped模式下多余间距
第一个section上边多余间距处理 // 隐藏UITableViewStyleGrouped上边多余的间隔 _tableView.tableHeaderView = [[UIView alloc] ...
- 利用国外服务器搭建ss
wget --no-check-certificate https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/s ...
- Algorithm --> 棋盘中求出A到B的最小步数
求出A到B的最小步数 给定象棋盘,以及位置A和B, 求出从A到B的最小步数 代码: #include <cstdio> #include <iostream> #include ...
- Algorithm --> Dijkstra和Floyd最短路径算法
Dijkstra算法 一.最短路径的最优子结构性质 该性质描述为:如果P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k,s)必 ...
- KVM之五:KVM日常管理常用命令
1.查看.编辑及备份KVM 虚拟机配置文件 以及查看KVM 状态: 1.1.KVM 虚拟机默认的配置文件在 /etc/libvirt/qemu 目录下,默认是以虚拟机名称命名的.xml 文件,如下,: ...
- java程序在没有java环境的电脑上执行的方法(关键词jar,exe)
可以让你写的java程序在别人没有任何java配置以及环境的情况下执行 写好程序 在程序对应的package上右键->export->java->Runnable JAR file- ...
- 201621123062《Java程序设计》第一周学习总结
1.本周学习总结 关键词: 初步熟悉Java的基本组成.语言特点(简单性.结构中立性).运行环境.简单语法等. 关键概念之间的联系: 1.JVM是Java程序唯一认识的操作系统,其可执行文件为.cla ...
- 【iOS】Swift ?和 !(详解)
Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值, 也就是说变量不会有默认值,所以要求使用变量之前必须要对其初始化 .如果在使用变量之前不进行初始化就会报错: [ ...