第一篇:纯 React&纯 Redux
第一章 技术简介
React
A:React 是一个声明式、高效、灵活的、创建用户界面的 JavaScript 库
Redux
A:Redux 是一个 JavaScript 状态容器,提供科预测的状态管理
Redux 三大原则:单一数据源、state 只读、使用纯函数来执行修改
单一数据源:在整个应用的 state 被存储在一颗对象树中,并且这个对象树只存在于唯一一个 store 中。state 指的是数据。
1 |
|
state 只读:并不代表我们不能修改 state 。只读指的是不想允许直接对 state 这个变量重写赋值,但可以通过 action 和 reducer 返回一个新的 state。
1 |
|
使用纯函数来执行修改:更新 state 的 reducer 只是一些纯函数,接收先前的 state 和 action, 并返回新的 state。
1 |
|
Q:为什么使用 Redux
A:可预测、便于组织管理代码、支持 Universal 渲染、优秀的拓展能力、容易测试、开发工具、社区和生态系统
为什么使用 Redux
可预测:Redux 是一个数据源,想要修改它只能发起 action。reducer 又是纯函数,也就是说输入永远会得到相同的输出。这一切让程序运行变得可控、可预测。
便于组织管理代码:严格而明确的程序结构使得代码更容易组织和管理。
支持 Universal 渲染:单一数据源这个原则可以帮助解决 Universal 渲染中的数据传输问题,服务器渲染后只需给客户端传递一个变量即可,这个变量就存储 state 的对象树
优秀的拓展能力:很多的中间件拓展
容易测试:写单一功能的、没有外界以来的小型函数
开发工具:可以通过使用 redux 开发工具实现追踪、回退和重放程序中的 action 和 state
Node&Universal 渲染
React&Redux 是实现 Universal 渲染的理想技术组合
Babel
Babel 是一个 JavaScript 编译器
Babel 工具
- Babel 内建工具:Babel CLI、Require Hook
- 各种构建系统:Webpack、Gulp、Grunt、RequireJs 等
- 测试框架:Jasmin、Karma、Mocha 等
- 语言 API:C#/.NET、Node、Ruby
- 模板引擎:Jade
- 编辑器:WebStrom
- 调试器:Node Inspector
Webpack
前端资源模块化管理和打包工具。通过加载器 (loader) 的转换,任何形式的资源都可以视为模块
- 编译、加载使用 ES2015 和 JSX 语法的模块
- 实现开发服务器和热替换
- 加载图片文件
- 加载字体文件
- 加载样式文件
- 加载 Json 文件
- 使用同构工具实现同构渲染
- 压缩代码
- 哈希命名
总结
第二章 在 Node.js 中运行 React
编写 React 组件
通常我们需要写一个继承 (extends) 自 React.Component 的类,并在 render() 中返回你要展示的视图
1 |
|
当如果这个组件只有一个 render 方法,可以写成下面的无状态组件,这也是 Aribnb 编码规范推荐的写法
1 |
|
export 就是抛出这个组件,default 表示你能在别的文件中使用 import App form './App'
导入这个组件。如果没有 default 则需要 import { App } form './App'
导入这个组件。
在 Node.js 中渲染组件
在src/server.js
中引入 (import) 上面的组件,然后将其渲染成一个 HTML 字符串打印出来。在 Node.js 中我们使用renderToString()
方法将组件渲染成字符串
1 |
|
使用 Babel 编译运行 Node.js 程序
使用 Require Hook 给每一个 require 方法上加上一个钩子,每次使用 require 加载 JavaScript 文件事,先使用 Babel 进行编译
注意:Require Hook 优势是将编译和运行合二为一,造成劣势是性能消耗大,所以只在测试环境中使用
1.Require Hook 安装:npm i babel-register --save-dev
- 使用:在入口文件顶部添加
require("babel-register")
1 |
|
- 安装 ES2015 和 React 的预设
1 |
|
- 添加配置文件
./babelrc
,激活 ES2015 和 React 预设
1 |
|
运行
1 |
|
总结
使用模块
react.js [必需]
React 是用来构建用户界面的 js 库,属于 view 层。
它有两大特点:1,单向数据绑定;2,虚拟 DOM
安装:npm install --save react
babel-preset-react [必需]
react 转码规则。为所有 react 插件所设置的 babel 预设。有了它,才能识别转译 jsx 语法等。
安装:npm install --save-dev babel-preset-react
babel-preset-latest [必需]
es2015,es2016,es2017 转码规则。为所有 es6 插件所设置的 babel 预设,
有了它,诸如,es6 的箭头函数,类,等等语法特性才能向 es5 转换。
安装:npm install --save-dev babel-preset-latest
而这里使用的是babel-preset-es2015
具体的babel-preset-latest
配置看 minooo 的配置
react-dom.js [必需]
react.js 主要用来创建元素和组件,当你想在 html 中渲染你的组件的时候,
你还得需要 react-dom.js。同时,react-dom.js 依赖于 react.js。
安装:npm install --save react-dom
第三章 在浏览器中运行 React
例子:
1 |
|
组件复用
把第二章的 App.js 复制过来
在浏览器中渲染 React
1 |
|
以上代码将<App />
组件渲染到 ID 为 app 的标签中
1 |
|
使用 Webpack 打包编译
- 安装 Webpack 和 babel-loader
1 |
|
- 添加 webpack.config.js 文件指定打包编译的配置信息
1 |
|
- 同样需要安装 ES2015 和 React 的预设
1 |
|
- 添加配置文件
./babelrc
,激活 ES2015 和 React 预设
1 |
|
总结
react.js [必需]
React 是用来构建用户界面的 js 库,属于 view 层。
它有两大特点:1,单向数据绑定;2,虚拟 DOM
安装:npm install --save react
react-dom.js [必需]
react.js 主要用来创建元素和组件,当你想在 html 中渲染你的组件的时候,
你还得需要 react-dom.js。同时,react-dom.js 依赖于 react.js。
安装:npm install --save react-dom
webpack [必需]
于人而言,尤其是当开发大型项目时,每个包每个模块每个静态资源都应尽可能的条理清晰的罗列出来,
这样方便我们开发;于机器而言,就不需要这么“条理清晰”了,此时应最大限度的压缩优化这些资源,
如何把这些资源模块“杂糅”在一起,这就是 webpack 要做的。
安装:npm install --save-dev webpack
备注:webpack 2.0 即将发布
webpack 最基本的启动 webpack 命令
webpack -w 提供 watch 方法,实时进行打包更新
webpack -p 压缩混淆脚本,这个非常非常重要!
webpack -d 生成 map 映射文件,告知哪些模块被最终打包到哪里了,方便调试
webpack –progress 显示打包进程,百分比显示
webpack –config XXX.js //使用另一份配置文件(比如 webpack.config2.js)来打包 webpack –colors 输出结果带彩色,比如:会用红色显示耗时较长的步骤
webpack –profile 输出性能数据,可以看到每一步的耗时
webpack –display-error-details 方便出错时能查阅更详尽的信息(比如 webpack 寻找模块的过程),从而更好定位到问题。
webpack –display-modules 默认情况下 node_modules 下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块
webpack 入门配置
babel-preset-react [必需]
react 转码规则。为所有 react 插件所设置的 babel 预设。有了它,才能识别转译 jsx 语法等。
安装:npm install --save-dev babel-preset-react
babel-preset-latest [必需]
es2015,es2016,es2017 转码规则。为所有 es6 插件所设置的 babel 预设,
有了它,诸如,es6 的箭头函数,类,等等语法特性才能向 es5 转换。
安装:npm install --save-dev babel-preset-latest
而这里使用的是babel-preset-es2015
具体的babel-preset-latest
配置看 minooo 的配置
第四章 开发服务器和热替换
例子
1 |
|
之前直接同 webpack 打包,每次修改后都需要先运行一次npm run build
,再手动刷新浏览器,效率实在是太低了。懒癌发作,使用开发服务器(webpack-dev-server)和热替换(hot-reloadeing)技术解决这个问题
配置 Babel
配置 Babel 时期支持热替换的最快捷方式是使用react-hmre
1 |
|
react-hmre 功能
这个预设的第一个功能是热替换 React 模块,还可以捕获错误,并将包含错误对战信息的红色警告页面输出到浏览器。
注意:如果将无状态组件放在组件顶层,热替换将会出错,所以现在的 App 组件是类组件。
配置 Webpack
1 |
|
配置 Express 服务器
在 Express 服务器中添加 webpackDevMiddleware 和 webpackHot-Middleware 两个中间件就能完成开发服务器和热替换的配置工作。
webpackDevMiddleware:将 webpack 的打包功能与 Express 服务器的资源服务功能合二为一。Express 通过它打包并把资源读取到内存中,它还可以监视代码变动,就会停止提供久资源,等编译完成后继续提供新资源
webpackHot-Middleware:webpackDevMiddleware 中间件无法完成热替换,也不能在更新后保留程序状态。为了实现热替换,还应该在 webpackDevMiddleware 基础上加上 webpackHot-Middleware
1 |
|
总结
####babel-core [必需]
Babel 是一个转换编译器,它能将 ES6 转换成可以在浏览器中运行的代码。
作为下一代 javascript 语言标准,请拥抱 ES6(ES2015) 吧!babel-core
是 Babel 编译器的核心。
安装:npm install --save-dev babel-core
####babel-loader [必需]
loader 用于转换应用程序的资源文件,他们是运行在 nodejs 下的函数,
使用参数来获取一个资源的来源并且返回一个新的来源针对 webpack 的 babel 加载器。babel-loader
就是告诉 webpack 去加载我们写的使用了 es6 语法的 js 文件。
安装:npm install --save-dev babel-loader
babel-preset-react [必需]
react 转码规则。为所有 react 插件所设置的 babel 预设。有了它,才能识别转译 jsx 语法等。
安装:npm install --save-dev babel-preset-react
babel-preset-latest [必需]
es2015,es2016,es2017 转码规则。为所有 es6 插件所设置的 babel 预设,
有了它,诸如,es6 的箭头函数,类,等等语法特性才能向 es5 转换。
安装:npm install --save-dev babel-preset-latest
而这里使用的是babel-preset-es2015
具体的babel-preset-latest
配置看 minooo 的配置
react.js [必需]
React 是用来构建用户界面的 js 库,属于 view 层。
它有两大特点:1,单向数据绑定;2,虚拟 DOM
安装:npm install --save react
react-dom.js [必需]
react.js 主要用来创建元素和组件,当你想在 html 中渲染你的组件的时候,
你还得需要 react-dom.js。同时,react-dom.js 依赖于 react.js。
安装:npm install --save react-dom
webpack [必需]
于人而言,尤其是当开发大型项目时,每个包每个模块每个静态资源都应尽可能的条理清晰的罗列出来,
这样方便我们开发;于机器而言,就不需要这么“条理清晰”了,此时应最大限度的压缩优化这些资源,
如何把这些资源模块“杂糅”在一起,这就是 webpack 要做的。
安装:npm install --save-dev webpack
备注:webpack 2.0 即将发布
webpack 最基本的启动 webpack 命令
webpack -w 提供 watch 方法,实时进行打包更新
webpack -p 压缩混淆脚本,这个非常非常重要!
webpack -d 生成 map 映射文件,告知哪些模块被最终打包到哪里了,方便调试
webpack –progress 显示打包进程,百分比显示
webpack –config XXX.js //使用另一份配置文件(比如 webpack.config2.js)来打包 webpack –colors 输出结果带彩色,比如:会用红色显示耗时较长的步骤
webpack –profile 输出性能数据,可以看到每一步的耗时
webpack –display-error-details 方便出错时能查阅更详尽的信息(比如 webpack 寻找模块的过程),从而更好定位到问题。
webpack –display-modules 默认情况下 node_modules 下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块
webpack 入门配置
webpack-dev-middleware [开发需要]
它是一个用来组织包装 webpack 使其变成中间件的容器。(中间件的用途就是在输入和输出的过程中加工的一种手段)
webpack 本身只负责打包编译,webpack-dev-server 是协助我们开发的服务器,这个服务器底层是靠 express 操作的。
我们的页面如何在这个服务器上更新呢,首先是取得 webpack 打包好的资源,这就需要在请求
到响应
的过程中通过
express 的中间件取得资料, 而方法就是通过 webpack-dev-middleware 来实现。
这个中间件只在开发环境中使用,切忌用在生产环境中。
安装:npm install --save-dev webpack-dev-middleware
这个中间件有两点好处:
- 直接在内存中操作文件,而非磁盘中。这样处理速度更快。
- 在监视(watch)模式下,如果文件改变,中间件立即停止提供之前的 bundle,并且会延迟
请求回应,直到新的编译完成,如此一来,文件修改后,你可以直接刷新页面,而不用等待编译。
webpack-hot-middleware [开发需要]
webpack-dev-middleware
+webpack-hot-middleware
即可让我们用express
定制一个有热替换功能的webpack
开发服务器。
安装:npm install --save-dev webpack-hot-middleware
babel-preset-react-hmre
这个预设的第一个功能是热替换 React 模块,还可以捕获错误,并将包含错误对战信息的红色警告页面输出到浏览器。
1>npm install babel-preset-react-hmre --save-dev
express [开发需要]
基于 Node.js 平台,快速、开放、极简的 web 开发框架。
在这里用于配置开发服务器。
安装:npm install --save-dev express
第五章 React 的创新语法:JSX
JSX 简介
jsx 是一个看起来像 XML 的 JavaScript 语法扩展,这种语法允许你在 JavaScript 中写可嵌套的闭合标签,JSX 可以让组件的结构和组件之间的关系看上去更加清晰。
JSX 语法
- 类似 HTML:可以嵌套,可以自定义属性
- JavaScript 表达式
- 样式:内联样式不是字符串,而是对象
- 注释:标签字节点内的注释应该写在
{}
内 - 数组:数组会自动展开。注意,数组中每一项元素需要添加 key 属性
JSX 常用语法
类似 HTML
JSX 与 HTML 非常相似,可以嵌套多个 HTML 标签,也可以使用大部分符合 HTML 规范的属性,比如 style。如果往 HTML 中传入了 HTML 规范里没有的属性, React 不会显示它们,但是可以通过加上 data-
前缀的办法自定义属性。
1 |
|
注意:因为 JSX 终究还是 JavaScript ,而
class
和for
又是 JavaScript 的保留字,所有尽管 JSX 中的 HTML 标签大多数和 HTML 规范的一致,但是class
和for
这两个属性在 JSX 中需要写成className
和htmlFor
。
JavaScript 表达式
JSX 允许在闭合标签中使用 JavaScript 表达式,但是要被{}
包裹。 JavaScript 表达式要求必须有返回值,因此无法直接使用 if else
语句,但是可以使用三元操作表达式以及 ||
和 &&
这样的比较运算符来书写。如果确实需要使用 if else
语句,可以将其卸载函数中,然后在 {}
中调用。
1 |
|
样式
总体来说,样式分为内联式、内嵌式、链接式等,这里要讲解的是内联样式的写法。与 HTML 相似,JSX 中的内联样式也可以通过 style
属性来定义,但属性值不能是字符串而必须是对象,而且要注意对象的属性名需要使用驼峰命名法,例如需要把 font-size
写成 fontSize
。
1 |
|
注释
在 JSX 中添加注释非常简单,只需要注意将标签字节点内的注释写在 {}
中就可以了。
1 |
|
数组
JSX 中的数组会自动展开所有成员。但是需要注意,如果数组或迭代器中的每一项都是 HTML 标签或组件,那么它们必须要拥有唯一的 key
属性。这样做是为 React 的 DIFF 算法服务的,React 会通过唯一的 key
属性实现最高效的 DOM 更新。
1 |
|
HTML 标签 vs. React 组件
React 可以渲染 HTML 标签或 React 组件。HTML 使用小写字母的标签名,而 React 组件的标签名首字母需要大写
1 |
|
第六章 React 的数据载体:state、props 与 context
State:应该成为局部状态或内部状态。
props:用于在组件间传递数据,仅支持逐层传递
context:用于在组件间传递数据,能够跨级传递
State
React 组件可以通过在构造函数中初始化内部状态,可以通过this.setState
方法更新内部状态,还可以使用this.state
获取内部状态。
1 |
|
首先在构造函数中初始化内部状态,然后给 button 的点击事件注册了一个更新内部状态的方法,最后将内部状态序列化显示在 pre 标签中。
随着无状态函数(无状态函数没有内部状态)的提出和 Redux 的使用,内部状态的使用正在逐渐减少。但是内部状态在非全局的数据管理更新中仍扮演着重要的角色。
Props
props 就是属性的意思
使用 props
向一个组件传递 props 的方法是将数据卸载组件标签的属性中
1 |
|
组件怎么获取传递过来的 props 呢?在无状态函数编写的组件中获取 props 非常简单。只需要将 props 作为参数传入组件即可
1 |
|
使用类编写的组件中,需要通过 this.props 获取 props 。this 是组件实例。
验证 Props
验证 props 需要用到 React.PropTypes,它提供很多验证器(validator)来验证传入的数据是否合法。当想 props 传入非法数据时,控制台会抛出警告。
PropTypes 提供的验证器
1 |
|
1 |
|
组合使用 state 与 props
这里用了一个 Counter 组件更新 state.value,然后将更新的 state.value 通过 props 传递给 Content 组件,最后 Content 组件在每次更新时都渲染出新接受到的 props.value
1 |
|
Context
context 在 React 中并不常用到,后面的 react-redux 会用到 context。现在先拿出之前的 props 和 context 做比较。
使用 props 传递数据
编写三个组件,分别是 Button 、Message 和 MessageList,在 MessageList 中定义一个 color 变量,通过 props 将 color 传递给 Button 组件
1 |
|
使用 context 传递数据
要使用 context 传递数据,需要两个步骤
- 将要传递的数据放在消息列表组件(数据发起位置)的 context 中
- 在按钮组件(接收数据的子组件位置)中声明 contextTypes,就可以通过 context 传递数据
1 |
|
第七章 React 的两个对象:ReactElement 与组件实例
ReactElement:就是传说中的“虚拟 DOM”,本质是个不可变的对象
组件实例:React 组件类的实例化对象,它通常用来管理内部状态和处理生命周期函数
ReactElement
JSX 中的闭合标签是 ReactElement
注意:只有在 React 中使用 JSX,闭合标签才是 ReactElement,在其他框架(比如 Vue)中使用 JSX 就不是 ReactElement
ReactElement 是什么
ReactElement 是一个不可变的普通对象,它描述了一个组件的实例或一个 DOM 节点。它只包含组件的类型(比如 h1,或者 APP)、属性以及子元素等信息。
ReactElement 不是组件是实例,不能在 ReactElement 中调用 React 组件的任何方法。它只是告诉 React 你想显示什么。
ReactElement 的两种类型
- type 属性是一个字符串时,它表示一个 DOM 节点,它的 props 属性对应 DOM 节点的属性
- type 属性是一个表示组件的函数或者类,它表示一个组件
React 组件的渲染流程
当 React 遇到表示组件的 ReactElement 时,它会给这个 ReactElement 表示的组件一些 props(有时也包括 context),然后问该组件渲染的 ReactElement 是什么。如果渲染的仍然是表示组件的 ReactElement,那么将会一直吻下去,直到了解所以组件要渲染的 DOM 元素为止,此时,React 就可以使用 react-dom 或者 react-native 这样的渲染模快来执行渲染。
组件实例
大多数情况下,我们无需直接创建组件实例,React 会负责创建它。ReactDOM.reder 返回的就是组件实例。除此之外,组件的 this 也指向组件实例。利用 Refs 可以获取组件实例。
注意:无状态函数是没有实例化对象的,因此无法使用生命周期函数,也没有内部状态。所以当你的组件需要使用生命周期函数或者内部状态,请使用类编写该组件。
组件、ReactElement 与组件实例的区别
组件是一个函数或类,它决定了如何把数据变成视图;ReactElement 只是一个普通的对象,它描述了组件实例或 DOM 节点;组件实例则是组件类的实例化对象。
组件实例的生灭:声明周期函数
- componentWillMount:在渲染前调用
- componentDidMount:在渲染后调用
- componentWillReceiveProps:在组件接收到一个新的 props 时被调用,这个方法第一次渲染时不会被调用
- shouldComponentUpdate:返回一个布尔值,在组件接收到新的 props 或者 state 时被调用。在初始化时或者使用
forceUpdate
时不被调用。可以在你确定不需要更新组件时使用。 - componentWillUpadte:在组件接收到新的 props 或者 state 但还没有 render 时被调用。在初始化时不被调用。
- componentDidupdate:在组件完成更新后立即调用。在初始化时不被调用
- componentWillUnmount:在组件从 DOM 中移除的时候立即被调用
React 组件中的 this
那些方法的 this 指向组件实例呢?怎么样才能在自定义的组件方法中获得组件实例?
React 组件的 this 到底是什么?
1 |
|
结果是,render() 函数中的 this 指向组件实例,而 handler() 函数中的 this 则是一个 null。
JavaScript 函数中的 this
JavaScript 函数中的 this 不是在函数声明的时候而是在函数运行的时候定义的。
1 |
|
student.speak() 打印了 student 对象,因为 this 指向 student 对象。而 studentSpeak() 打印了 window,因为 this 指向了 window
关于 this 绑定
React.createClass 可以自动绑定所有的方法,使 this 指向组件的实例化对象。在类组件中,上下文转换的自动权交给了开发者,通常我们在构造函数中绑定方法
1 |
|
将 this.handler() 绑定上下文为组件实例后, this.handler() 中的 this 将指向组件实例。此处也可以用箭头函数或者在属性中临时绑定,不过 Aribnb 编码规范并不推荐在 JSX 的属性中使用 bind 临时绑定,所以尽量在构造函数中进行绑定或者使用箭头函数。
第八章 初识 Redux
Action、reducer、state、store 是 Redux 中的一些基本概念。
Action
Action 本质是 JavaScript 普通对象,action 内使用一个字符串类型的 type 字段来表示将要执行的动作。除了 type 字段外,action 对象的结构完全由你决定。
发起 ation:
1 |
|
其中{type:’DECREMENT’}和{type:’INCREMENT’}就是 action
Reducer
Reducer 是个形式为 (state,action)=>state 的纯函数,描述了 action 如何把 state 转变成下一个 state。reducer 是一个累加器函数,它的参数是上一个累加值和数组当前元素,然后通过计算得到当前的累加值。在 Redux 中,state 就是那个累加值,action 就是数组当前的元素。
1 |
|
State 可以是任何类型、数组、对象等等,唯一要点是当 state 变化时需要返回全新的对象,而不是修改传入的参数。
纯函数
纯函数不能访问外部变量,只能接收传入参数。纯函数不能修改参数,因为这样做可能会把一些信息通过传入参数夹带到外界。
还不完整
不能修改参数 state
在 JavaScript 中对象是引用类型,修改了参数 state,变化前后的两个 state 将会指向同一个地址,react-redux 就会认为这是两个相同的 state,因而不会执行渲染。
Store
职能
store 是一个全局对象,作用是将 action 和 reducer 以及 state 联系在一起。
- 维持应用的 state
- 提供 getState() 方法获取 state
- 提供 dispatch(action) 方法更新 state
- 通过 subscribe(listener) 注册监听器
创建
1 |
|
获取与监听
1 |
|
发起 action
Store 通过 dispatch(action) 方法发起 action,更新 state
1 |
|
当发起 action 后,就将 action 传进了 store,使用 reducer 纯函数执行更新。修改 state 唯一方法就是 dispatch(action),所有的变化都将进过这条路,我们把中间件放在 dispatch 这条路上。
第九章 Action 创建函数与 Redux Thunk 中间件
Action 创建函数
编写
1 |
|
发起
1 |
|
Redux Thunk 中间件
这个中间件能让 action 创建函数先不返回 action,而是返回一个函数。通过函数处理后再 dispatch。
1 |
|
安装激活
1 |
|
本笔记是我读 《React 与 Redux 开发实例精解》基础篇的学习笔记,所以笔记中大量摘抄了原书的内容,笔记中的代码来源于书作者的开源项目 react-redux-book。往后我还会在博客里更新更多的读书笔记,当然读书笔记的内容并不完善,如果需要详细内容请购买《React 与 Redux 开发实例精解》