title: react文档2-深入react
date: 2018.9.21
tags:


高级指南: http://react.css88.com/docs/optimizing-performance.html

2018.9.21 星期五 10:21

8 与第三方库协作

本指南将列举一些更常见的用例,重点介绍与 jQuery 以及 Backbone 的集成,但同样的思路适用于将组件与任何现有代码集成。
## 与 DOM 操作类插件结合
## 在 React 中使用其他引擎加载页面
## 在 React 中使用其他数据层库和框架
一般来说,推荐大家使用符合单向数据流的框架和库,比如 React state、Flux 或 Redux。但 React 的组件也可以支持其他处理数据流的框架和库。

2 代码拆分(Code-Splitting)

## 打包(Bundling)
大多数的 React 应用程序使用Webpack或 Browserify 等工具来 “打包” 文件。
如果你使用的是Create React App,Next.js,Gatsby 或类似的工具,您将拥有一个开箱即用的 Webpack 安装程序来打包你的应用程序。
## 代码拆分
### import()

动态 import() 语法是ECMAScript(JavaScript)提案,目前不是语言标准的一部分。预计在不远的将来会被接受。

当 Webpack 遇到这个语法时,它会自动启动 代码拆分 来拆分你的应用程序。 如果您正在使用 Create React App ,则已经为你配置好了
在使用 Babel 时,你需要确保 Babel 能够解析动态导入语法,但目前 Babel 还不能直接对其进行转换。
## 库(Libraries)
React Loadable
## 基于路由的代码拆分



14. 一致性比较(Reconciliation)

React提供声明式API,因此在每次更新中你不需要关心具体的更改内容。
React 的 “diffing” 算法中我们所作出地决择,以使得组件的更新是可预测的并且可以适用于高性能应用。

动机

当你使用 React ,在任何一个单点时刻你可以认为 render() 函数的作用是创建 React 元素树。在下一个 state 或props 更新时,render() 函数将会返回一个不同的 React 元素树。接下来 React 将会找出如何高效地更新 UI 来匹配最近时刻的 React 元素树。

目前存在大量通用的方法能够以最少的操作步骤将一个树转化成另外一棵树。然而,这个算法是复杂度为O(n3),其中n 为树中元素的个数。

如果你在 React 中展示 1000 个元素,那么每次更新都需要10亿次的比较,这样的代价过于昂贵。然而,React 基于以下两个假设实现了时间复杂度为 O(n) 的算法:

  1. 不同类型的两个元素将会产生不同的树。
  2. 开发人员可以使用一个 key prop 来指示在不同的渲染中那个那些元素可以保持稳定。
    事实上,这些假设在几乎所有的用例中都是有效的。

Diffing 算法

当比较不同的两个树,React 首先比较两个根元素。根据根跟的类型不同,它有不同的行为。

### 元素类型不相同
### DOM元素类型相同
保留相同的底层 DOM 节点,只更新反生改变的属性(attributes)
### 相同类型的组件
当一个组件更新的时候,组件实例保持不变,以便在渲染中保持state。React会更新组件实例的属性来匹配新的元素,并在元素实例上调用 componentWillReceiveProps() 和 componentWillUpdate()。

接下来, render() 方法会被调用并且diff算法对上一次的结果和新的结果进行递归。
### 子元素递归
默认情况下,当递归一个 DOM 节点的子节点时,React 只需同时遍历所有的孩子基点同时生成一个改变当它们不同时。
如果在开始处插入一个节点也是这样简单地实现,那么性能将会很差。
### Keys
当子节点有了 key ,React 使用这个 key 去比较原来的树的子节点和之后树的子节点。
这个key 需要在它的兄弟节点中是唯一的就可以了,不需要是全局唯一。

$_索引做为key在排序中会有问题:
作为最后的手段,你可以将数组中的索引作为 key 。如果它们从不重新排序,它们工作也很好,但是如果存在重新排序,性能将会很差。

当索引用作key时,组件状态在重新排序时也会有问题。组件实例基于key进行更新和重用。如果key是索引,则item的顺序变化会改变key值。这将导致受控组件的状态可能会以意想不到的方式混淆和更新。

权衡利弊

需要记住的是 reconciliation(协调) 算法仅仅只是一个实现细节。React 会在每个操作上重新渲染整个应用,最终的结果可能是相同的。我们经常细化启发式算法,以便优化性能。

因为React 依赖这个启发式,如果它们背后的假设没有得到满足,性能将会受到影响。



12. React 中不使用 ES6

通常情况下你可以用普通的 JavaScript 类定义一个组件:
如果你不使用 ES6 ,你可以使用 create-react-class 方法代替:
除了一些例外,ES6 classes(类) API 非常类似于函数 createReactClass()

var createReactClass = require('create-react-class');
var Greeting = createReactClass({
  render: function() {
    return <h1>Hello, {this.props.name}</h1>;
  }
});

## 声明默认 Props
## 设置初始化 State(状态)
## 自动绑定
在 createReactClass() 中,并不需要这么做,因为方法可以自动绑定。
## Mixins
$_MORE:

ES6 是不支持 mixin 的,因此,当你用 ES6 classes(类)编写 React 时是不支持 mixins 的。
我们也在使用 mixins 的情况下发现了部分问题,所以我们不推荐目前使用。

有时不同的组件可能会共用部分方法,这些方法会被称为横切关注点(cross-cutting concerns)。createReactClass 可以允许你使用 mixins 。

13. React 中不使用 JSX

JSX 对使用React 不是必须的。当你不想在你的构建环境中设置编译器,那么不使用 JSX 的 React 是非常方便的。

每一个 JSX 元素都是调用 React.createElement(component, props, …children) 的语法糖,因此,任何你使用 JSX 来做事都可以通过纯 JavaScript 实现。

如果你厌倦了使用 React.createElement ,另一个常见的模式是将其赋值给一个缩写

9 深入 JSX

从本质上讲,JSX 只是为 React.createElement(component, props, …children) 函数提供的语法糖。JSX代码:

<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>
// 编译为  
React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)
React.createElement(
  'div',
  {className: 'sidebar'},
  null
)

指定 React 元素类型

一个 JSX 标签的开始部分决定了 React 元素的类型。

首字母大写的标签指示 JSX 标签是一个 React 组件。这些标签会被编译成 命名变量 的直接引用。所以如果你使用 JSX 表达式,那么 Foo 必须在作用域中。

### React 必须在作用域中
### 对 JSX 类型使用点语法
### 用户定义组件必须以大写字母开头
### 在运行时选择类型

JSX 中的 props(属性)

### JavaScript 表达式作为 props(属性)
在 JavaScript 中,if 语句和 for 循环不是表达式,因此不能在 JSX 中直接使用。但你可以将他们放在附近的代码块中
### 字符串字面量
### props(属性) 默认为 “true”
通常情况下,我们不建议使用这种类型,因为这会与ES6中的对象shorthand混淆 。
### 属性展开
你也可以挑选你的组件将使用的指定属性(props),同时使用展开运算符传递所有其他属性(props)。
展开(Spread) 属性可能很有用,但它们还可以轻松地将不必要的属性(props)传递给不关心它们的组件,或将无效的HTML属性传递给DOM。我们建议谨慎使用此语法。

JSX 中的 Children

在 JSX 表达式中可以包含开放标签和闭合标签,标签中的内容会被传递一个特殊的 props(属性) : props.children,下面有好几种方式传递 children :
### 字符串字面量
### JSX Children
所以你可以混用字符串字面量和 JSX children。这是 JSX 与 HTML 另一点相似的地方,
### JavaScript 表达式作为 Children(子元素)
### Functions(函数) 作为 Children(子元素)
然而, props.children 类似于其他的 props(属性) ,可以被传入任何数据,而不是仅仅只是 React 可以渲染的数据。
只要在渲染之前组件可以将其转化为 React 能够处理的东西即可。这种用法并不常见,但是如果你需要扩展 JSX 的话,则会非常有用。
### Booleans, Null, 和 Undefined 被忽略
false,null,undefined,和 true 都是有效的的 children(子元素) 。但是并不会被渲染,
需要注意的是“falsy”值,例如数值 0 ,仍然会被 React 渲染。

10 优化性能

## 使用生产版本
chrome插件
## 使用 Chrome 性能分析工具 分析组件性能
## 虚拟化长列表:“windowing” (开窗口) 技术
## 避免重新渲染
在大多数情况下,您可以不用手写 shouldComponentUpdate() ,而是从 React.PureComponent 继承。 这相当于用当前和以前 props(属性) 和 state(状态) 的浅层比较来实现shouldComponentUpdate() 。

## 应用 shouldComponentUpdate
## 例子
在这种情况下,shouldComponentUpdate 函数仅仅检查 props.color 或者 state.count 是否发生改变。如果这些值没有发生变化,则组件不会进行更新。如果你的组件更复杂,你可以使用类似于对 props 和 state 的所有属性进行”浅比较”这种模式来决定组件是否需要更新。这种模式非常普遍,因此 React 提供了一个 helper 实现上面的逻辑:继承 React.PureComponent 。因此,下面的代码是一种更简单的方式实现了相同的功能:
## 不可变数据的力量
concat 重写,ES6 对于数组支持展开语法,Object.assign 方法,JavaScript提案添加了对象展开符
## 使用 Immutable 数据结构

12:21