[关闭]
@llqintel 2017-02-14T10:15:12.000000Z 字数 4161 阅读 1523

深入React技术栈笔记

前端


初识React

  1. React并不是完整的MVC/MVVM框架,它专注与提供清晰,简洁的View层解决方案。但又与模板引擎不同,React还包括Controller

Vue算是MVVM?
与Vue区别?
Virtual DOM
DOM操作性能消耗较大,React把真实的DOM树转换成js对象树,即Virtual DOM。
每次数据更新后,重新计算VM,并和上次生成的VM对比,发生变化的部分做批量更新。React还提供了直观的shouldComponentUpdate,来减少不必要的VM对比。
优点
VM提升了React的性能,但DOM节点的比对也需要计算资源,所以提升不明显。
最大的好处就是方便和其他平台集成。
函数式编程

函数式编程
命令式:就像给电脑下命令(C,Java等)
声明式:整个过程变成构建在f函数作用在要处理的.. React把不断重复构建UI的过程抽象成组件,而且给定特定参数的情况下约定渲染对应的UI界面。

JSX语法
只允许一个标签被包裹
标签一定要闭合
DOM元素小写,组件元素首字母大写
注释 要用{}包裹起来
元素属性 class=>className for=>htmlFor
Boolean属性 使用属性表达式<Checkbox checked={false}/>
展开属性可以使用ES6 rest/spread
<C {...this.props}>
html转义
默认都是转义,防止XSS

  1. //不转义
  2. <div dangerouslySetInnerHTML={{__html: 'cc&copy; 2015'}}></div>

React组件

组件的演变
React组件与Web Components
组件设计

  1. 基本封装性
  2. 生命周期的呈现
  3. 明确的数据流动(参数)

Web Components组成部分

  1. HTML Template
  2. Custom Elements 组件展示形式
  3. Shadow DOM 组件的作用域范围
  4. HTML Imports 新的引入方式

React组件

  1. 自定义元素是库自己创建的,与Web Components规范不通用
  2. 包含了模板的概念,即jsx
  3. 实现均在方法和类中,可以做到相互隔离,但不包括css
  4. 遵循ES6 module规范

无状态组件
不存在state, 也没有生命周期方法。创建时始终保持了一个实例,避免了不必要的检查和内存分配,做到了内部优化。
没有shuouledComponentUpdate,每次都渲染

React数据流

在React中,数据是自顶向下流动,即父元素到子元素。

setState是异步方法,一个生命周期内setState方法会合并操作。
智能组件:内部更新
木偶组件:外部更新

设计React组件时,一定要满足一个原则:直观。组件如果能分解,一定要分解。

  1. React.Children.map
  2. React.cloneElement

事件系统

Virtual DOM在内存中以对象的形式存在,如果想在这些对象上添加事件,非常简单。
注意点:JSX中必须以驼峰来书写事件名
实现机制

  1. 事件委托: 把所有事件绑定到最外层,使用一个统一的事件监听器。简化可事件的处理和回收机制,效率也有很大提升。
  2. 自动绑定: 自动绑定this为当前组件,ES6 class或者纯函数时,需要手动绑定bind
  3. 双冒号语法
  4. <button onClick={::this.handleClick}>确定</button
  5. 构造器内绑定
  6. 箭头函数

使用原生事件
在组件卸载时需要手动移除,否则可能会早生内存泄露的问题。
阻止React事件冒泡的行为对原生事件不起作用,而原生事件中却可以阻止React事件冒泡。
不要混用原生与React事件

表单

受控组件

每当表单的状态发生变化,都会被写入state中。

  1. 消除局部状态,使得整个应用的状态更可控
  2. 在执行setState之前,对表单进行校验与处理
  3. 使用defaultValuedefaultChecked来设置默认值
  4. 表单值每次发生变化都要调用一次

非受控组件

一个表单组件没有value props(或checked prop)

状态属性

value

  1. input textarea select

checked

  1. radio

select

  1. option

CSS Modules

CSS模块化解决方案

  1. inline style 彻底抛弃css,使用jsjson来书写css,能够css提供js一样强大的模块化能力。但不能使用媒体查询,:hover,:active等伪类处理起来也比较复杂。
  2. CSS Modules

要解决的问题:
全局污染:样式命名重复,容易被覆盖
命令混乱
依赖管理不彻底:引入组件时,除了需要引入js还需要单独引入css
无法共享变量
代码压缩不彻底

CSS模块化的解决方案

引入:import和:export两个伪类
结合webpack的css-loader,就可以利用js来管理css。只转换class相关的样式,id选择器,伪类,标签选择器不做处理

  1. css?modules&localIdentName=[name]_[local]-[hash:base64]:5

使用composes组合样式

  1. .base { .. }
  2. .normal{
  3. composes: base;
  4. ..

CSS命名技巧

对应模块名,节点名,节点状态

css与js变量共享

:export关键字

与React结合

可以使用react-css-modules库,避免重复输入styles

组件间通信

父组件向子组件

  1. 通过props

子组件向父组件

  1. 回调函数
  2. 自定义事件,如vueon绑定, emit触发

跨级组件通信

  1. 父子层层传递
  2. 使用context实现,但犹如全局变量一样会带来一些副作用,除了界面主题,用户信息等真正全局意义的信息否则不建议使用context

没有嵌套关系的组件通信

  1. 自定义事件(发布订阅模式,Node.js Events模块)

组件抽象

mixin

类似的概念:拷贝继承,组合
单继承在实现抽象时有一些不变之处,为了弥补缺失,java引入接口,而js引入类似mixin的技巧,创造类似于多继承的效果。
实现

  1. 把一个对象原型的方法拷贝给另一个对象(可选择拷贝)
  2. 同名覆盖
  3. 深度拷贝,浅拷贝

jQuery中实现方法是extend(支持深度拷贝),ES6中Object.assign

  1. //浅拷贝
  2. function mixin(dest, src){
  3. var destProto = dest.prototype,
  4. srcProto = src.prototype;
  5. for(var key in srcProto){
  6. console.log(key);
  7. if(!(key in destProto)) destProto[key] = srcProto[key]
  8. }
  9. }

React中mixin不同之处

  1. 同名方法不会覆盖,而会报错
  2. 生命周期方法叠加在一起顺序执行

通过decorator(修饰器)与ES6 class来实现mixin

mixin的问题

  1. 破坏了原有组件的封装,添加了新的方法,但也引入了新的stateprops,意味着组件的不可见状态也需要我们去维护。mixin也可能依赖其他的mixin,这样会建立一个mixin依赖链。
  2. 命名冲突
  3. 增加复杂性,维护性差

高阶组件(higher-order-component)

类似于higher-order-function(高阶函数):接收函数输入或是输出函数,比如map, reduce , sort等
实现方法如下:

属性代理

通过高阶组件来传递props
控制props
可以读取,增加或是移除传入原生组件的props
通过refs使用引用
ref回调函数来实现,拿到原始组件的参数
抽象state
将原始组件作为展示型组件,分离内部状态
使用其他元素包裹
增加样式或者布局

mixin与高阶组件的区别
mixin是侵入式的,高阶组件无侵入,符合函数式编程思想。对于原始组件来说,并不会感知到高阶组件的存在,只要把功能套在上面就可以,从而避免了mixin产生的副作用。

反向继承

高阶组件返回的组件继承于原始组件,高阶组件可以使用原始组件的引用,使用原始组件的state,props,生命周期和render方法

渲染劫持
高阶组件可以控制原始组件的渲染结果。
控制state
高阶组件可以读取,修改或删除原始组件的state,不过尽量避免这样做,可以通过重新命名state,以防止混淆
组件命名
displayname
组件参数

一些细节整理

判断对象是否具有某属性

  1. //之前做法
  2. if(props.activeIndex){
  3. //一些操作
  4. }
  5. //上面代码存在隐式转换,如果activeIndex为false,0或者其他Boolean(activeIndex)===false的值,则会出错
  6. if('activeIndex' in props){
  7. ..
  8. }

React Router

路由的实现方式:hashchange与pushState

hashchange
pushState
replaceState
popstate

React同构

http://www.tuicool.com/articles/juMjAnj

调用setState之后发生了什么

React.children.map

React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object

flux

业务与数据解耦
容器组件 展示组件
解决混乱的数据流动方式
核心思想数据和逻辑永远单向流动
所有的请求和控制只能从action发起,统一由dispatcher来分配。
view可以保持足够的简洁,不需要关心太多的逻辑;
MVC下数据或逻辑的改动可以来自完全不同的源头,Flux架构追查问题的复杂度和困难显然要小很多。

viwe->action->dispatcher->store->view

Redux

单一数据源, combineReducers
状态是只读的
flux中没有setter而限制了我们直接修改应用的能力,而在redux中执行的更彻底,根本没有store
状态修改均由纯函数完成
与Flux的最大不同,flux中直接修改了store中的数据,导致无法保存每次数据变化前后的状态。而redux中,每一个reducer都是纯函数,即接受一定的输入,必定会得到一定的输出。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注