一、初入React世界
1、React简介
专注视图层,React 并不是完整的 MVC/MVVM 框架,它专注于提供清晰、简洁的 View (视图)层解决方案
Virtual Dom,每次数据更新后,重新计算 Virtual DOM,并和上一次生成的 Virtual DOM 做对比,对发生 变化的部分做批量更新
函数式编程,React 把过去不断重复构建 UI 的过程抽象成了组件,且在给定参数的情况下约 定渲染对应的 UI 界面。React 能充分利用很多函数式方法去减少冗余代码。
2、JSX语法
2.1、JSX由来
DOM元素,原生DOM元素
组件元素,自定义元素,JSX 将 HTML 语法直接加入到 JavaScript 代码中
2.2、JSX基本语法
2.2.1、XML基本语法
定义标签时,只允许被一个标签包裹。原因是一个标签会被转译成对应的 React.createElement 调 用方法,外层没有被包裹,显然无法转译成方法调用。
标签一定要闭合。
2.2.2、元素类型
小写首字母对应 DOM 元素,而组件元素自然对应大写首字母。2.2.3、元素属性
class 属性改为 className, for 属性改为 htmlFor
在写自定义属性的时候,都由标准写法改为小驼峰写法。
2.2.4、boolean属性
省略 Boolean 属性值会导致 JSX 认为 bool 值设为了 true,不写属性则默认为false2.2.5、展开属性
使用 ES6 rest/spread 特性:const component = <Component {...data} />;
2.2.6、自定义 HTML 属性
如果要使用 HTML 自定义属性,要使用 data- 前缀,这与 HTML 标准也是一致的2.2.7、JavaScript 属性表达式
属性值要使用表达式,只要用 {} 替换 "" 即可2.2.8、Babel
原名6to5是一个开源的转译工具,支持转译最新的JavaScript特性,也支持转译JSX2.2.9、JSX和表单
onChange属性订阅属性发生的改变,在用户输入时触发
value属性总是和文本输入框的最新内容保持一致,defaultValue指定默认值
3、React组件
3.1、组件的演变
狭义上的组件,又称为 UI组件,比如Tabs组件、Dropdown组件。组件主要围绕在交互动作上的抽象,针对这些交互动作,利用 JavaScript 操作 DOM 结构或 style 样式来控制。
广义上的组件,即带有业务含义和数据的 UI 组件组合。这类组件不仅有交互动作,更重 要的是有数据与界面之间的交互。
3.2、React组件的构建
React 组件基本上由 3 个部分组成——属性(props)、状态(state)以及生命周期方法。
React 组件可以接收参数,也可能有自身状态。一旦接收到的参数或自身状态有所改变, React 组件就会执行相应的生命周期方法,然后渲染
3.3、React组件的构建方法
React.createClass 构建组件是 React 传统、也是兼容性好的方法。
ES6 classes 的写法是通过 ES6 标准的类语法的方式来构建方法
无状态组件只传入 props 和 context 两个参数;也就是说,它不存在 state,也没有生命周 期方法,组件本身即上面两种 React 组件构建方法中的 render 方法
4、React数据流
4.1、state
在 React 中,数据是自顶向下单向流动的,即从父组件到子组件。这条原则让组件之间的关 系变得简单且可预测。
当组件内部使用库内置的 setState 方法时,大的表现行为就是该组件会尝试重新渲染
4.2、props
组件的 props 一定来自于默认属性或通过父组件传递而来。
React 为 props 同样提供了默认配置,通过 defaultProps 静态变量的方式来定义
在 React 中有一个重要且内置的 prop——children,它代表组件的子组件集合。children 可 以根据传入子组件的数量来决定是否是数组类型。
组件props
如果组件定义了propTypes,那么在开发环 境下,就会对组件的 props 值的类型作检查
5、React生命周期
5.1、挂载或卸载过程
组件挂载是基本的过程,这个过程主要做组件状态的初始化。componentWillMount 和 componentDidMount
组件卸载非常简单,只有 componentWillUnmount 这一个卸载前状态,在 componentWillUnmount 方法中,我们常常会执行一些清理方法,如事件回收或是清除定 时器。
5.2、数据更新过程
更新过程指的是父组件向下传递 props 或组件自身执行 setState 方法时发生的一系列更新 动作
如果组件自身的 state 更新了,那么会依次执行 shouldComponentUpdate、componentWillUpdate 、 render 和 componentDidUpdate方法。
shouldComponentUpdate 是一个特别的方法,它接收需要更新的 props 和 state,让开发者增加 必要的条件判断,让其在需要时更新,不需要时不更新。因此,当方法返回 false 的时候,组件 不再向下执行生命周期方法。
如果组件是由父组件更新 props 而更新的,那么在 shouldComponentUpdate 之前会先执行 componentWillReceiveProps 方法。
6、ReactDom
DOM 真正被添加到 HTML 中的生命周期方法是 componentDidMount 和 componentDidUpdate 方法
findDOMNode 返回该 React 组件实例相应的 DOM 节点。它可以 用于获取表单的 value 以及用于 DOM 的测量
render:为要把 React 渲染的 Virtual DOM 渲染到浏览器的 DOM 当中,就要使用 render 方法
refs 即 reference,组件被调用时会新建一个该组件的实例,而 refs 就会指向这个实例。
二、漫谈React
1、事件系统
1.1、合成事件的绑定方式
虚拟DOM在内存中是以对象的形式的存在的
合成事件支持事件的冒泡机制,stopPropagation()、preventDefuault()
JSX代码表示为按钮添加点击事件:<button onClick={this.handleClick}>Test</button>
1.2、合成事件的实现机制
事件委派:事件处理函数不会绑定到真实的节点上,而是把所有的事件绑定到结构的最外层,使用统一的事件监听器,这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数
自动绑定:在react组件中每个方法的上下文都指向该组件的实例,即自动绑定this为当前组件,但使用es6 class或者纯函数时,这种自动绑定就不复存在,需要手动实现this的绑定
- bind方法:
render(){ return <button onClick={this.handleClick.bind(this, 'test')}>Test</button>; }
- 双冒号语法:不传参数:
render(){return <button onClick={::this.handleClick}>Test</button>; }
- 构造器内声明:在constructor(){}内部声明
this.handleClick = this.handleClick.bind(this);
- 箭头函数:箭头函数还自动绑定了此函数的作用域this,
<button onClick={()=>{this.handleClick}}>Test</button>;
1.3、在React中使用原生事件
React 中使用 DOM 原生事件时,一定要在组件卸载时手动移除,否则很 可能出现内存泄漏的问题。而使用合成事件系统时则不需要,因为 React 内部已经帮你妥善地处 理了。合成事件与原生事件混用
避免在React中混用合成事件和原生事件,比如:在原生事件中使用合成事件
可以通过e.target判断来避免
1.4、对比React合成事件与JS原生事件
阻止事件传播在React中只需要使用e.preventDefault()
React合成事件是JS原生事件的一个子集
事件绑定方式,React合成事件的绑定方式简单很多:<button onClick={this.handleClick}>Test</button>
事件对象,在React不存在兼容性问题
2、表单
2.1、应用表单组件
在React中一切数据皆是状态
文本框:value来表示表单的值
单选框和复选框:value值一般不会改变,checked来表示选中状态
select组件:设置select标签的multiple={true}来实现的一个多选下拉列表
2.2、受控组件
受控组件:每当表单发生变化时都会写入组件的state中
- 初始state中设置表单的默认值
- 每当表单的值发生变化时,调用onChange事件处理器
- 事件处理器合成事件对象e拿到改变后的状态,并更新应用的state
- setState触发视图的重新渲染,完成表单组件值的更新
- 数据是单向流动的,表单中数据源于组件中的state,并通过props传入,又通过onChange事件处理器将数据写会组件的state,完成双向数据绑定
非受控组件:表单组件中没有value 或 checked,可以使用defaultValue和defaultChecked来表示组件的默认状态
对比受控组件和非受控组件:
- 非受控组件的状态不会受应用状态的控制,受控组件的值来自于组件中state
- 受控组件需要绑定onChange事件处理器
表单组件的几个重要属性:
状态属性:
- value:类型为 text 的 input 组件、textarea 组件以及 select 组件都借助 value 来展示 应用的状态。
- checked:类型为 radio 或 checkbox 的组件借助值为 boolean 类型的 selected 来展示 应用的状态。
- selected:该属性可作用于 select 组件下面的 option 上,React 并不建议使用这种方式表 示状态,而推荐在 select 组件上使用 value 的方式。
事件属性:当状态属性发生变化时,会触发onChange事件属性
3、基本样式设置
自定义组件支持className
设置行内样式style时,需要使用对象
与大小有关的样式时,react会自动添加px
4、组件间通信
父组件向子组件通信,React 数据流动是单向的,父组件向子组件的 通信也是常见的方式。父组件通过 props 向子组件传递需要的信息。
子组件向父组件通信,利用回调函数,利用自定义事件机制
跨级组件通信,使用 context 来 实现跨级父子组件间的通信、
没有嵌套关系的组件通信
5、组件间抽象
mixin
高阶组件:属性代理,反向继承
6、组件性能优化
6.1、纯函数
给定相同的输入,它总是返回相同的输出
过程没有副作用
没有额外的状态依赖
6.2、PureRender
PureRender本质,PureRender 中 的 Pure 指的就是组件满足纯函数的条件,即组件的渲染是被相同的 props 和 state 渲染进而得到 相同的结果。
运用PureRender,利用 createClass 构建组件时,可以使用官方的插件,其名为 react-addons-pure-render-mixin。 此外,用 ES6 classes 语法一样可以使用这个插件
优化PureRender:
- 直接为 props 设置对象或数组
- 设置 props 方法并通过事件绑定在元素上
- 设置子组件
6.3、Immutable
Immutable Data 就是一旦创建,就不能再更改的数据Immutable 的优点:降低了“可变”带来的复杂度,节省内存,撤销/重做,复制/粘贴,甚至时间旅行这些功能做起来都是小菜一碟,并发安全,拥抱函数式编程。
Immutable 的缺点:容易与原生对象混淆是使用 Immutable 的过程中遇到的大的问题,Immutable.is比较的是两个对象的hashCode 或 valueOf, Immutable 与 cursor,由于 Immutable 数据一般嵌套非常深, 所以为了便于访问深层数据,cursor 提供了可以直接访问这个深层数据的引用