目录
1、React是什么
2、React 三大颠覆性的特点
2.1 组件
2.2 JSX
2.3 Virtual DOM
3、Flux 架构(redux)
3.1 Flux
3.2 redux
4、打包工具(webpack)
4.1 webpack与RequireJS、browserify
4.2 模块规范
4.3 非 JavaScript 模块支持
4.4 webpack 的特点与优势
React 是 Facebook 推出的一个 JavaScript 库,它的口号就是“用来创建用户界面的 JavaScript 库”,所以它只是和用户界面打交道,你可以把它看成 MVC 中的 V (视图) 这一层。
React 的一切都是基于组件的,组件有着良好的封装性,组件可以让代码的复用和测试变得更加简单。各个组件都有着各自的状态,当状态变更时,便会重新渲染整个组件,组件化开发不仅仅应用于 React ,这也是 Web 的发展的趋势。
组件初始化:
组件更新:
组件卸载:
props 属性用于父子组件传值。
state 是当前组件保存的状态信息。
组件的生命周期包括组件初始化,更新,卸载对应的钩子函数。
无状态函数式组件是组件内部没有 state ,不需要组件的生命周期,这类组件可以写成一个纯函数,它只是根据输入生成组件,没有其他的副作用。
state 设计原则应遵循最小化 state 的准则,存储最简洁的数据,一下数据不应该包含到 state 中:
DOM操作,props 中的数据,props 可以看做是数据的来源。
一种直接把 HTML 嵌套在 JS 中的写法,一种类似 XML 的写法,它可以定义类似 HTML 一样简洁的树状结构,JSX 作为一种编译器,可以把类似 HTML 的结构编译成 JavaScript 。
Virtual DOM是一种对于 HTML DOM 节点的抽象描述,是一种用 JavaScript 实现的结构,不需要浏览器 DOM API 支持,将组件的 DOM 结构映射到 Virtual Dom 上,当需要重新渲染是,React 在 Virtual DOM 上实现了一种 Diff 算法,通过算法找到需要更新的节点,然后把里面的修改更新到实际需要修改的 DOM 节点上,这样可以避免渲染整个 DOM 带来的成本。
1、DOM
DOM (文档对象模型),它是 HTML,XML,XHTML 的一种抽象描述。把文档转换成树类型的数据结构,成为 DOM tree,随着树结构越来越复杂,以及对 DOM 节点的添加,删除或修改,事件的监听,回调,销毁需要处理,会导致大量 reflow,影响网页的性能。
2、Virtual DOM
Virtual DOM 是独立 React 所存在的,是用完全轻量的数据格式来代替庞杂的 DOM 结构来表述相同的内容。
可以用 JSX 来一种创造 ReactElement 的便捷写法。
ReactElement 是一种轻量级的、无状态的、不可改变的、DOM元素的虚拟描述。
3、比较差异
构建 Virtual DOM 树结构
var tree = new Element ('div', {props: {id: 'test'}},'hello there');
将 Virtual DOM 树插入到真正的 DOM 中
var root = render (tree, document.getElementById(container));将 Virtual DOM 树插入到真正的 DOM 中
var root = render (tree, document.getElementById(container));通过 Diff 算法计算出两颗树的不同
var patches = diff (tree, newTree);
DOM 元素变更,使用 patch 方法,将计算的不用作用于Dom 上
patch(root, patches);
1、Actions:帮助向Dispatcher传递数据的辅助方法;
2、Dispatcher:接收action,并且向注册的回调函数广播payloads;
3、Store:应用程序状态的容器&并且含有注册到Dispatcher的回调函数;
4、View:React组件,从Store获取状态,并将其逐级向下传递给子组件。
redux 是 Flux 架构的一种实现,redux 的三大特性:
(1) 单一数据源
整个应用的state 存储在一个 JavaScript 对象上,用一个 store 的对象来存储整个 state 。
(2) state 是只读的
不能直接在 state 上面直接修改数据,唯一的方法只能通过触发 Action 这一动作。
(3) 使用纯函数执行修改
为了描述 action 怎样改变 state ,需要编写 reducer 来规定修改的规则。
redux 的几个组成部分:
(1) action
action 是信息的载体,里面有action 的名称和要传递的信息,通过store 的 dispatch 方法传递,action 是 store 唯一信息来源。
(2) reducer
action 定义了执行的操作,而reducer 就是定义state 如何响应。
(3) store
store 则是保存整个工作流。
redux 的工作流:
redux 开发工具
Redux DevTools 是Redux作者开发的辅助工具,提供很强大的功能,主要有:
(1) 查看 store state 与 action 的内容。
(2) 撤销或重新执行 action 的能力,即所谓的“时间旅行” (Time Travel)。
(3) 修改 reducer 代码后自动重新执行先前的 action 一会应用状态。
(4) reducer 错误捕捉。
(5) 借助 persistState() store 增强工具,可以在刷新页面后恢复应用先前的状态。。
反模式
在软件工程中,反模式的定义是在实践中明显出现但又低效或是有待优化的设计模型,用来解决问题的带有共同性的不良方法。一下列举几种在 React 中情况:
(1) 基于 props 得到初始的 state
得到 state 的值,不一定是不对的,但是如果用 props 而得到 state 的值,可能会导致维护 state 逻辑的正确性。
(2) 使用 refs 获取子组件
通过 refs 去获取子组件,从而调用子组件里面的方法,这样会导致这种调用行为难以追踪。
(3) 冗余事实
例如 state 的数据,如果谋一份数据可能不止一个来源,我们在所有消费这个数据的时候,会导致结果不一致的问题。
(4) 组件的隐式数据源
如果某个组件直接去获取数据源,会导致组件行为不可预测,组件可复用性下降,一般情况下,我们的数据都是由父组件显式地传递进来。
(5) 不被预期的副作用
在组件的 render 方法或 store 的 reducer 实现中,触发 action 或调用组件的 setState ,操作 DOM 发送 AJAX 请求等都是反模式的。
性能优化
(1) 避免过早的优化,着眼瓶颈。
(2) 性能分析,一般涉及到业务代码的行为,react 的行为。
(3) 区分生产和开发版本。
(4) 避免不必要的render,在组件的生命周期中的一个钩子, shouldComponentUpdate方法,会获取两个参数 nextProps 和 nextState ,常见的实现是对新旧 porps 和 state 进行比较,进而判断是否进行 render。
(5) 合理地拆分组件。
(6) 合理地使用组件内部的 state。
webpack 作为一款打包工具,功能强大,配置灵活,特有的 code spliting方案正戳中了大规模复杂web应用的痛点,简单loader/plugin开发使它很快拥有丰富的配置功能与生态。
RequireJS 是一个模块加载器,基于AMD(Asynchronous Module Definition)规范实现。
RequireJS 往往是一个个单独的文件,RequireJS 从入口开始,递归地进行静态分析,找出所有直接或间接被依赖(require)的模块,然后进行转换与合并。
// bundle.js
define('hello', [], function(require){
module.export = 'hello'
});
define(say, ['require', 'hello'], function(require){
var hello = require('./hello')
});
browserify 是Node.js 模块为出发点的工具,最大的特点有两点:
(1)对CommonJS规范(Node.js 模块所采用的规范)的模块代码进行的转换与包装。
(2)对很多Node.js 的标准 package 进行了浏览器的适配,只要是遵循CommonJS规范的 JavaScript 模块,即使是纯前端代码,也可以用他打包。
RequireJS 本身依照 AMD 规范来实现,例如:
define ( function ( require ) {
module.exports = 'hello';
})
AMD 将模块实现的代码通过匿名函数( 即 AMD 的工厂方法,factory) 中实现作用域的隔离,通过文件的路径作为模块 ID 实现命名空间的控制,将模块的工厂方法作为参数传入全局的 define ( 由模块加载器事先定义),使得工厂方法的执行时机可控,也相当于变相模拟出了同步的局部 require ,因而 AMD 的模块可以不经转换的在浏览器中执行。
Browserify 支持的则是 CommonJS规范的 JavaScript 模块。例如:
// hello.js
module.exports = 'hello';
相比 RequireJS 的 AMD 规范,去掉了 define 以及工厂方法的外壳,所以是无法直接在浏览器中执行,但是在 NodeJS环境中, CommonJS 模块书写起来更加简单和干净,所以很多前端项目开始采用 CommonJS 规范的模块方式。
在组件化开发的越来越流行的趋势下,我们应将局部的逻辑进行封装,通过尽可能少的接口与其他组件进行组装和交互,可以将逻辑大的项目逻辑拆成一个个小的相对独立的部分,以减少开发和维护的负担。
在 RequreJS 的方案中,非 JavaScript 模块的资源虽然得到了支持,但支持的并不完善。
在 browserify 中,可以通过各种 transform 插件实现不同类型的引入与打包。
在 webpack 中, 与 browserify 的 transform 相对应得是 loader ,但是功能更加丰富。
(1) 代码拆分(code splitting) 方案
可以将应用代码拆分为多个快( chunk ) , 每个块包含一个或多个模块,块可以按需异步加载。
(2) 智能的静态分析
可以将应用代码拆分为多个块( chunk ) , 每个块包含一个或多个模块,块可以按需异步加载。
(3) 模块热替换
当修改完某一个模块后无需刷新页面,即可动态将受影响的模块替换为新的模块,以便执行新的模块逻辑。