github编辑

React 教程之从概念到实战

React 教程之从概念到实战

前端三大框架之一,用于构建用户界面的 JavaScript 库

一、React 入门

1.1 React 的基本认识

React 官网:

介绍描述:

React 是用于构建用户界面的 JavaScript 框架(只关注于 View)

  • JS 库&框架:

    • jQuery——函数库(方法、函数包装 DOM 操作)

    • React 基本上不操作 DOM——JS 框架

  • 构建用户界面:把数据展现出来

  • Facebook开源

React 的特点:

  • Declarative(声明式编码)

    • 不需要亲自操作 DOM(申请一块内存,只需要声明一个变量即可),只需要告诉它,我要更新,就会帮你更新,只需要更新数据,界面不需要手动更新(以前需要更新 DOM)

  • Component-Based(组件化编码)

    • 简化特别复杂的功能,可以拆分为多个简单的部分(一个小的界面功能就是一个组件),维护也方便

  • Learn Once, Write Anywhere(支持客户端与服务器渲染)

    • 一次学习,随处编写:不仅能写 web 应用,还能通过 React Native 打包为 Android、IOS 应用

  • 高效

  • 单向数据流

React 高效的原因(区域、次数——更新界面效率提高):

  • 虚拟(virtual)DOM,不总是直接操作 DOM

    • 虚拟 DOM:对象——与组件对应,修改映射到真实的 DOM 上(批量修改、界面重绘次数少

  • DOM Diff 算法,最小化页面重绘

    • 界面中组件是否更新(更新区域小

1.2 React 的基本使用

注意:此时只是测试语法使用, 并不是真实项目开发使用

实现效果:将 h1 标签利用 react 放到 test 中

React基本使用

相关的库:

  • react.js:React 的核心库

    • development.js:开发版,开发编写的时候使用

    • production.min.js:生产版,上线的时候使用,压缩过的

  • react-dom.js:提供操作 DOM 的 React 扩展库

  • babel.min.js:解析 JSX 语法代码转为纯 JS 语法代码的库,这里不是 ES6 转 ES5(jsx 是 js 扩展语法)

可以到 bootcdn 引用地址,访问链接 Ctrl + S 保存到本地

在页面中导入 js

开始编码

使用 React 开发者工具调试

React Developer Toolarrow-up-right

1.3 React JSX

实现效果:两个 #test 分别加入相应内容

React JSX

代码:

虚拟 DOM

  • React 提供了一些 API 来创建一种 特别 的一般 js 对象

    • var element = React.createElement('h1', {id:'myTitle'}, 'hello')

    • 上面创建的就是一个简单的虚拟 DOM 对象,babel 将会把 jsx 语法转为上述的形式

  • 虚拟 DOM 对象最终都会被 React 转换为真实的 DOM(虚拟 DOM 中的对应真实 DOM 中的标签元素)

  • 我们编码时基本只需要操作 react 的虚拟 DOM 相关数据,react 会转换为真实 DOM 变化而更新界面

补充知识:debugger 可以在某条 js 代码处添加断点

虚拟 DOM——轻对象,更新虚拟 DOM 页面不重绘

真实 DOM——重对象,更新真实 DOM 页面会发生变化(页面重绘)

JSX

  • 全称:JavaScript XML

  • react 定义的一种类似于 XML 的JS 扩展语法:XML+JS

  • 作用:用来创建 react 虚拟 DOM(元素)对象

  • 例如:var ele = <h1>Hello JSX!</h1>

  • 注意1:它不是字符串,也不是 HTML/XML 标签

  • 注意2:它最终产生的就是一个 JS 对象

  • 标签名任意:HTML 标签或其它标签

  • 标签属性任意:HTML 标签属性或其它

  • 基本语法规则

    • 遇到 < 开头的代码, 以标签的语法解析:html 同名标签转换为 html 同名元素,其它标签需要特别解析

    • 遇到以 { 开头的代码,以 JS 语法解析:标签中的 js 代码必须用 {} 包含

babel.js 的作用

  • 浏览器不能直接解析 JSX 代码,需要 babel 转译为纯 JS 的代码才能运行

  • 只要用了 JSX,都要加上 type="text/babel",声明需要 babel 来处理

渲染虚拟 DOM(元素)

  • 语法:ReactDOM.render(virtualDOM, containerDOM)

  • 作用:将虚拟 DOM 元素渲染到页面中的真实容器 DOM 中显示

  • 参数说明

    • 参数一:纯 js 或 jsx 创建的虚拟 dom 对象

    • 参数二:用来包含虚拟 DOM 元素的真实 dom 元素对象(一般是一个 div)

建虚拟 DOM 的 2 种方式

  • 纯 JS(一般不用) React.createElement('h1', {id:'myTitle'}, title)

  • JSX: <h1 id='myTitle'>{title}</h1>

JSX 练习:动态展示列表数据

JSX

代码:

1.4 模块与组件和模块化与组件化的理解

模块

  • 理解:向外提供特定功能的 js 程序,一般就是一个 js 文件

  • 为什么:js 代码更多更复杂

  • 作用:复用 js,简化 js 的编写,提高 js 运行效率

有特定功能的 js 文件,内部有数据及对数据的操作

  • 数据:变量

  • 操作:函数

私有的函数向外暴露

  • 暴露一个函数:暴露函数本身

  • 暴露多个函数:以对象形式暴露

组件

  • 理解:用来实现特定(局部)功能效果代码集合(html/css/js)

  • 为什么:一个界面的功能更复杂

  • 作用:复用编码,简化项目编码,提高运行效率

模块化

  • 当应用的 js 都以模块来编写的,这个应用就是一个模块化的应用

  • 形容项目或编码

组件化

  • 当应用是以多组件的方式实现,这个应用就是一个组件化的应用

例如下面 App 组件就是一个组件,它又是由多个组件组成的

  • CommentAdd 组件

  • CommentList 组件

    • 多个 CommentItem 组件

component

二、React 面向组件编程

面向对象 → 面向模块 → 面向组件

2.1 基本理解和使用

实现效果

组件

组件标签:可以随便取的标签,首字母大写(与 HTML 标签区分开)

自定义组件(Component):

  1. 定义组件(2 种方式)

    • 方式 1:工厂函数组件(简单组件:没有状态的组件)——效率高,不需要创建对象

    • 方式 2:ES6 类组件(复杂组件)——需要创建对象,有了状态只能使用这种方式

  2. 渲染组件标签

注意

  • 组件名必须首字母大写

  • 虚拟 DOM 元素只能有一个根元素

  • 虚拟 DOM 元素必须有结束标签

render() 渲染组件标签的基本流程

  1. React 内部会创建组件实例对象

  2. 得到包含的虚拟 DOM 并解析为真实 DOM

  3. 插入到指定的页面元素内部

2.2 组件三大属性 1:state

实现效果

state

理解

  • state 是组件对象最重要的属性,值是对象(可以包含多个数据)

  • 组件被称为"状态机",通过更新组件的 state 来更新对应的页面显示(重新渲染组件)

编码操作

  1. 初始化状态:

  2. 读取某个状态值

  3. 更新状态-->组件界面更新

实现代码

2.3 组件三大属性 2:props

实现效果

props

理解

  • 每个组件对象都会有 props(properties 的简写)属性

  • 组件标签的所有属性都保存在 props

作用

  • 通过标签属性从组件外向组件内传递变化的数据

  • 注意:组件内部不要修改 props 数据

编码操作

  1. 内部读取某个属性值 this.props.propertyName

  2. props 中的属性值进行类型限制和必要性限制

    注意:

    自 React v15.5 起,React.PropTypes 已移入另一个包中。请使用 prop-typesarrow-up-right 代替。需要先引入该库。

    我们提供了一个 codemod 脚本arrow-up-right来做自动转换。

  3. 扩展属性:将对象的所有属性通过 props 传递 <Person {...person}/>

  4. 默认属性值

  5. 组件类的构造函数

代码

🔖 面试题:请区别一下组件的 propsstate 属性

  • state组件自身内部可变化的数据

  • props:从组件外部向组件内部传递数据,组件内部只读不修改

2.4 组件三大属性 3:refs 与事件处理

效果

props_event

refs 属性

  • 组件内的标签都可以定义 ref 属性来标识自己

    1. <input type="text" ref={input => this.msgInput = input}/>

    2. 回调函数在组件初始化渲染完或卸载时自动调用

  • 在组件中可以通过 this.msgInput 来得到对应的真实 DOM 元素

  • 作用:通过 ref 获取组件内容特定标签对象,进行读取其相关数据

事件处理

  • 通过 onXxx 属性指定组件的事件处理函数(注意大小写)

    • React 使用的是自定义(合成)事件, 而不是使用的原生 DOM 事件

    • React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素)

  • 通过 event.target 得到发生事件的 DOM 元素对象

强烈注意

  • 组件内置的方法中的 this 为组件对象

  • 在组件类中自定义的方法中 thisnull

  • 强制绑定 this:通过函数对象的 bind() / apply() / call() 来指定 this

  • 箭头函数没有 this,箭头函数内部的 this 是上下文中的 this(箭头函数没有自己的 this,它的 this 是外面的 this

代码

2.5 组件的组合

效果

component组合使用

功能界面的组件化编码流程(无比重要)

  1. 拆分组件:拆分界面,抽取组件

  2. 实现静态组件:使用组件实现静态页面效果(只有静态界面,没有动态数据和交互)

  3. 实现动态组件

    • 实现初始化数据动态显示

    • 实现交互功能(从绑定事件监听开始)

代码

2.6 收集表单数据

效果

component表单 (2)

理解

  • 问题:在 react 应用中,如何收集表单输入数据

  • 包含表单的组件分类

    • 受控组件:表单项输入数据能自动收集成状态

    • 非受控组件:需要时才手动读取表单输入框中的数据

代码

2.7 组件生命周期

效果

component生命周期

理解

  • 组件对象从创建到死亡它会经历特定的生命周期阶段

  • React 组件对象包含一系列的勾子函数(生命周期回调函数),在生命周期特定时刻回调

  • 在定义组件时,可以重写特定的生命周期回调函数,做特定的工作

生命周期流程图

生命周期流程图

Mount:挂载,将虚拟标签放到容器(页面)中

render() 渲染

左边初始化过程,这些方法称为声明周期回调函数,或称为生命周期的勾子,这些方法在特定的时刻调用

回调函数:你定义的,你没有调用,但是最终执行了;声明式编程,流程设定好,命令式编程 jQuery,每一步自己操作

will 将、did 完成

生命周期详述

  • 组件的三个生命周期状态:

    • Mount:插入真实 DOM

    • Update:被重新渲染

    • Unmount:被移出真实 DOM

  • React 为每个状态都提供了勾子(hook)函数,可重写

    • componentWillMount()

    • componentDidMount()

    • componentWillUpdate()

    • componentDidUpdate()

    • componentWillUnmount()

  • 生命周期流程:

    1. 第一次初始化渲染显示:ReactDOM.render()

      • constructor():创建对象初始化 state

      • componentWillMount():将要插入回调

      • render():用于插入虚拟 DOM 回调

      • componentDidMount():已经插入回调

    2. 每次更新 state:this.setSate()

      • componentWillUpdate():将要更新回调

      • render():更新(重新渲染)

      • componentDidUpdate():已经更新回调

    3. 移除组件:ReactDOM.unmountComponentAtNode(containerDom)

      • componentWillUnmount():组件将要被移除回调

三个阶段,可以都打印一下,看下方法执行的过程(与写的顺序无关,但推荐按阶段的顺序写,更直观)

重要的勾子

  • render():初始化渲染或更新渲染调用

  • componentDidMount():开启监听,发送 ajax 请求

  • componentWillUnmount():做一些收尾工作,如清理定时器

  • componentWillReceiveProps():后面需要时讲

代码

2.8 虚拟 DOM 与 DOM Diff 算法

虚拟 DOM:减少操作真实 DOM 的次数,更新界面次数变少

DOM Diff 算法:计算哪里需要更新,哪里不需要更新,减少更新界面的区域

共同提高更新界面的效率

效果

component虚拟DOM

只有时间更新,其他不更新

基本原理图

基本原理
  • 初始化:虚拟 DOM 树(div>p>span……),更新虚拟 DOM 界面不会变——>更新真实 DOM 界面才会变化(更新状态)

  • 更新(关键):调用 setState() 更新状态(会进行对比)——>根据差异更新真实 DOM、重绘页面变化的区域

三、react 应用(基于 react 脚手架)

3.1 使用 create-react-app 创建 react 应用

react脚手架

  • xxx脚手架:用来帮助程序员快速创建一个基于xxx库的模板项目

    • 包含了所有需要的配置

    • 指定好了所有的依赖

    • 可以直接安装/编译/运行一个简单效果

  • react 提供了一个用于创建 react 项目的脚手架库:create-react-app

  • 项目的整体技术架构为:react + webpack + es6 + eslint

  • 使用脚手架开发的项目的特点:模块化、组件化、工程化

创建项目并启动

浏览器访问 http://localhost:3000arrow-up-right

注:

C:\Users\Shinelon\AppData\Roaming\npm\node_modules

react 脚手架项目结构

package.json

  • "dependencies":运行时依赖

  • "devDependencies":开发时依赖,编译打包时需要,开发时不需要,编译打包时工具包

public/index.html 主界面

  • 只有一个 <div id="root"></div>,依靠组件

src/index.js 应用入口

  • 引入包(import * from "*")、CSS(import "*.css")

  • 渲染组件

README.md对项目的说明文件

SPA(Single Page Application):单应用

index.html

src/components/app.jsx

src/index.js

src/index.css

本地预览

cd react_app

npm startnpm run start

3.2 demo:评论管理

效果

demo_comment

拆分组件

拆分组件

应用组件:App

  • state: comments/array

添加评论组件:CommentAdd

  • state: username/string, content/string

  • props: add/func

评论列表组件:CommentList

  • props: comment/object, delete/func, index/number

评论项组件:CommentItem

  • props: comments/array, delete/func

实现静态组件

render(){return} 中的内容

src/index.js

src/components/app/app.jsx

src/components/comment-add/comment-add.jsx

src/components/comment-list/comment-list.css

src/components/comment-list/comment-list.jsx

src/components/comment-item/comment-item.css

src/components/comment-item/comment-item.jsx

实现动态组件

动态展示初始化数据

  • 初始化状态数据

  • 传递属性数据

响应用户操作, 更新组件界面

  • 绑定事件监听, 并处理

  • 更新 state

四、react ajax

4.1 理解

前置说明

  • React 本身只关注于界面,并不包含发送 ajax 请求的代码

  • 前端应用需要通过 ajax 请求与后台进行交互(json 数据)

  • react 应用中需要集成第三方 ajax 库(或自己封装)

常用的 ajax 请求库

  • jQuery:比较重,如果需要另外引入不建议使用

  • axios:轻量级,建议使用

    a. 封装 XmlHttpRequest 对象的 ajax

    b. promise 风格

    c. 可以用在浏览器端和 node 服务器端

  • fetch:原生函数,但老版本浏览器不支持

    a. 不再使用 XmlHttpRequest 对象提交 ajax 请求

    b. 为了兼容低版本的浏览器,可以引入兼容库 fetch.js

效果

ajax

4.2 axios

文档:

https://github.com/axios/axios

相关 API:

GET 请求

POST 请求

4.3 Fetch

文档

相关 API

GET 请求

POST 请求

4.4 demo:github users

效果

demo_users

拆分组件

拆分组件

编写静态组件、编写动态组件

componentWillReceiveProps(nextProps):监视接收到新的 props,发送 ajax

使用 axios 库发送 ajax 请求

public/index.html

src/index.js

src/index.css

src/components/app.jsx

src/components/search.jsx

src/components/user-list.jsx

五、几个重要技术总结

5.1 组件间通信

5.1.1 方式一:通过 props 传递

  • 共同的数据放在父组件上,特有的数据放在自己组件内部(state)

  • 通过 props 可以传递一般数据和函数数据,只能一层一层传递

  • 一般数据-->父组件传递数据给子组件-->子组件读取数据

  • 函数数据-->子组件传递数据给父组件-->子组件调用函数

父组件传到孙组件、兄弟组件之间不能直接通信,经过子组件、服务器传递

5.1.2 方式二:使用消息订阅(subscribe)-发布(publish)机制

工具库: PubSubJS

下载: npm install pubsub-js --save

使用:

以上一个用户搜索的 demo 为例,search 和 userlist(main) 之间需要通信,它们是兄弟组件

在这里是通过父组件,利用 props 进行通信

props-search

这是以前的 app.ejs

app.ejs

现在不通过父组件来通信

src/components/app.ejs

src/components/search.ejs

src/components/user-list.ejs

再以之前的评论的为例

App.ejs 中有个删除评论的函数,传给了 List 组件(并没有用到),接着传给 Item

5.1.3 方式三:redux

redux 是一个状态管理工具,后面专门讲解

5.2 事件监听理解

5.2.1 原生 DOM 事件

  • 绑定事件监听

    • 事件名(类型):只有有限的几个,不能随便写

    • 回调函数

  • 触发事件

    • 用户操作界面

    • 事件名(类型)

    • 数据

5.2.2 自定义事件(消息机制)

  • 绑定事件监听

    • 事件名(类型):任意

    • 回调函数:通过形参接收数据,在函数体处理事件

  • 触发事件(编码)

    • 事件名(类型):与绑定的事件监听的事件名一致

    • 数据:会自动传递给回调函数

5.3 ES 6 常用新语法

  • 定义常量/变量:const/let

  • 解构赋值:let {a, b} = this.propsimport {aa} from 'xxx'

  • 对象的简洁表达:{a, b}

  • 箭头函数:

    • 常用场景

      • 组件的自定义方法:xxx = () => {}

      • 参数匿名函数

    • 优点:

      • 简洁

      • 没有自己的 this,使用引用 this 查找的是外部 this

  • 扩展(三点)运算符:拆解对象/数组 (const MyProps = {}, <Xxx {...MyProps}>)

  • 类:class/extends/constructor/super

  • ES 6 模块化:export default | import

六、react-router 4

6.1 相关理解

6.1.1 react-router 的理解

  • react 的一个插件库(依赖/基于 React)

  • 专门用来实现一个 SPA 应用

  • 基于 react 的项目基本都会用到此库

6.1.2 SPA的理解

  • 单页 Web 应用(single page web application, SPA)

  • 整个应用只有一个完整的页面

  • 点击页面中的链接不会刷新页面,本身也不会向服务器发请求

  • 当点击路由链接时,只会做页面的局部更新

  • 数据都需要通过 ajax 请求获取,并在前端异步展现

6.1.3 路由的理解

  • 什么是路由?

    • 一个路由就是一个映射关系(key: value)

    • key 为路由路径(path),value 可能是 function(后台路由)/component(前台路由)

  • 路由分类

    • 后台路由:node 服务器端路由value 是 function,用来处理客户端提交的请求并返回一个响应数据

    • 前台路由:浏览器端路由,value 是 component,当请求的是路由 path 时,浏览器端前没有发送 http 请求,但界面会更新显示对应的组件

  • 后台路由

    • 注册路由:router.get(path, function(req, res))

    • 当 node 接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据

  • 前端路由

    • 注册路由:<Route path="/about" component={About}>

    • 当浏览器的 hash 变为 #about 时,当前路由组件就会变为 About 组件

6.1.4 前端路由的实现

底层实现:

history 库

  • 管理浏览器会话历史(history)的工具库

  • 包装的是原生 BOM 中 window.historywindow.location.hash

  • history API

    • History.createBrowserHistory():得到封装 window.history 的管理对象

    • History.createHashHistory():得到封装 window.location.hash 的管理对象

    • history.push():添加一个新的历史记录

    • history.replace():用一个新的历史记录替换当前的记录

    • history.goBack():回退到上一个历史记录

    • history.goForward():前进到下一个历史记录

    • history.listen(function(location){}):监视历史记录的变化

测试:

history-方式1
history-方式2

6.2 react-router 相关 API

react_routerarrow-up-right

react-router

webarrow-up-right

6.2.1 组件

  • <BrowserRouter>:BrowserRouter 是 react 路由的容器

  • <HashRouter>:这个是用来兼容老浏览器的

  • <Route>:Route 的作用就是用来渲染路由匹配的组件。路由渲染有三种方式,每一种方式都可以传递 match,location,history 对象

  • <Redirect>:路由重定向

  • <Link>:Link 的作用和 a 标签类似

  • <NavLink>:NavLink 和 Link 一样最终都是渲染成 a 标签,NavLink 可以给这个 a 标签添加额外的属性

  • <Switch>:Switch 组件内部可以是 Route 或者 Redirect,只会渲染第一个匹配的元素

6.2.2 其它

  • history 对象:这里的 history 对象是使用 history 插件生成的,http://www.cnblogs.com/ye-hcj/p/7741742.htmlarrow-up-right 已经详细讲过了

    • 记住一点,在使用 location 做对比的使用,通过 history 访问的 location 是动态变化的,最好通过 Route 访问 location

  • match对象:match 对象表示当前的路由地址是怎么跳转过来的

  • withRouter 函数:当一个非路由组件也想访问到当前路由的 match,location,history 对象,那么 withRouter 将是一个非常好的选择

6.3 基本路由使用

react-router demo

并没有刷新页面

准备

下载 react-router:npm install --save react-router@4

我们只需要web版本:npm install --save react-router-dom

由于使用到了 BootStrap,因此在 index.html 中引入 bootstrap.css: <link rel="stylesheet" href="/css/bootstrap.css">

public/index.html

一般会将路由组件和非路由组件分开写

pages/views 存放路由组件

components 存放其他组件

路由组件:views/about.jsx

路由组件:views/home.jsx

包装 NavLink 组件:components/my-nav-link.jsx,由于每个 NavLink 都需要自定义 active 样式(加入属性 activeClassName),因此提出来

应用组件:components/app.jsx

自定义样式:index.css

入口JS:index.js

总结:如何编写路由效果?

  1. 编写路由组件

  2. 在父路由组件中指定

    • 路由连接:<NavLink></NavLink>

    • 路由:<Route></Route>

6.4 嵌套路由使用

嵌套路由——路由组件中的路由

react-router demo2

二级路由组件:views/news.jsx

二级路由组件:views/message.jsx

一级路由组件:views/home.jsx

6.5 向路由组件传递参数数据

传递的是 id 值

react-router demo3 (2)

三级路由组件:views/message-detail.jsx

二级路由组件:views/message.jsx

路由链接与非路由链接:是否发了请求(路由连接不发)

  • <NavLink to=''></NavLink>

  • <Link to=''></Link>

  • <a href=''></a>

6.6 多种路由跳转方式

前面讲的路由切换都是通过点击链接的方式切换的,不是链接也能够

react-router demo4

二级路由:views/message.jsx

总结:

  • 路由器标签

    • <BrowserRouter>:BrowserRouter 是 react 路由的容器

    • <HashRouter>:多了一个 #

  • 路由

    • <Route>:Route 的作用就是用来渲染路由匹配的组件。路由渲染有三种方式,每一种方式都可以传递 match,location,history 对象

  • <Redirect>:路由重定向

  • 链接

    • <Link>:Link的作用和a标签类似

    • <NavLink>:可以添加其他属性,例如 activeClassName

  • <Switch>:Switch 组件内部可以是 Route 或者 Redirect,只会渲染第一个匹配的元素

  • this.props.

    • match

      • params

    • history

      • push()

      • replace()

      • goback()

      • goforward()

七、react-ui

7.1 最流行的开源 React UI 组件库

7.1.1 material-ui(国外)

7.1.2 ant-design(国内蚂蚁金服)

7.2 ant-design-mobile 使用入门

antd-mobile

使用 create-react-app 创建 react 应用

搭建 antd-mobile 的基本开发环境

下载 npm install antd-mobile --save

src/components/App.jsx

src/index.js

index.html

实现按需打包(组件 js/css)

下载依赖包

修改默认配置:package.json

config-overrides.js

编码

八、redux

8.1 redux 理解

学习文档

redux 是什么?

  • redux 是一个独立专门用于做状态管理JS 库(不是 react 插件库)

  • 它可以用在 react、angular、vue 等项目中,但基本与 react 配合使用

  • 作用:集中式管理 react 应用中多个组件共享的状态

redux 工作流程

redux

什么情况下需要使用 redux

  • 总体原则:能不用就不用, 如果不用比较吃力才考虑使用

  • 某个组件的状态,需要共享

  • 某个状态需要在任何地方都可以拿到

  • 一个组件需要改变全局状态

  • 一个组件需要改变另一个组件的状态

8.2 redux 的核心 API

8.2.1 createStore()

作用:创建包含指定 reducer 的 store 对象

编码:

8.2.2 store对象

作用:redux 库最核心的管理对象

它内部维护着:

  • state

  • reducer

核心方法:

  • getState()

  • dispatch(action)

  • subscribe(listener)

编码:

8.2.3 applyMiddleware()

作用:应用上基于 redux 的中间件(插件库)

编码:

8.2.4 combineReducers()

作用:合并多个 reducer 函数

编码:

8.3 redux的三个核心概念

8.3.1 action

标识要执行行为的对象

包含 2 个方面的属性

  • type:标识属性,值为字符串,唯一,必要属性

  • xxx:数据属性,值类型任意,可选属性

例子:

  • Action Creator(创建 Action 的工厂函数)

8.3.2 reducer

根据老的 state 和 action,产生新的 state 的纯函数

样例

注意

  • 返回一个新的状态

  • 不要修改原来的状态

8.3.3 store

将 state、action 与 reducer 联系在一起的对象

如何得到此对象?

此对象的功能?

  • getState():得到 state

  • dispatch(action):分发 action,触发 reducer 调用,产生新的 state

  • subscribe(listener):注册监听,当产生了新的 state 时,自动调用

8.4 使用 redux 编写应用

效果

redux

使用 react 实现

app.jsx
index.js

下载依赖包

src/redux/action-types.js

src/redux/actions.js

src/redux/reducers.js

src/components/app.jsx

src/index.js

也可以把 index.jsstore 提取出来

src/redux/store.js

src/index.js

问题

  • redux 与 react 组件的代码耦合度太高(大多数地方用到 store)

  • 编码不够简洁

8.5 react-redux

8.5.1 理解

  • 一个 react 插件库

  • 专门用来简化 react 应用中使用 redux

8.5.2 React-Redux 将所有组件分成两大类

  • UI 组件

    • 只负责 UI 的呈现,不带有任何业务逻辑

    • 通过 props 接收数据(一般数据和函数)

    • 不使用任何 Redux 的 API

    • 一般保存在 components 文件夹下

  • 容器组件

    • 负责管理数据和业务逻辑,不负责 UI 的呈现

    • 使用 Redux 的 API

    • 一般保存在 containers 文件夹下

8.5.3 相关API

Provider

让所有组件都可以得到state数据

connect()

用于包装 UI 组件生成容器组件

mapStateToprops()

将外部的数据(即 state 对象)转换为 UI 组件的标签属性

mapDispatchToProps()

将分发 action 的函数转换为 UI 组件的标签属性

简洁语法可以直接指定为 actions 对象或包含多个 action 方法的对象

8.5.4 使用 react-redux

下载依赖包

redux/action-types.js

不变

redux/actions.js

不变

redux/reducers.js

不变

components/counter.jsx

containers/app.jsx

store.js

不变

index.js

问题

  • redux 默认是不能进行异步处理的(前面的都是 react 实现的)

  • 应用中又需要在 redux 中执行异步任务(ajax、定时器等)

8.6 redux 异步编程

下载 redux 插件(异步中间件)

redux/store.js

index.js

redux/actions.js

同步的 action 都返回一个对象

异步的 action 返回的是一个函数

components/counter.jsx

containers/app.jsx

redux/action-types.js

8.7 使用上 redux 调试工具

安装 Chrome 浏览器插件

Redux DevToolsarrow-up-right

下载工具依赖包

编码

8.8 Redux 版评论

需求

使用 react_redux 和中间件实现异步评论功能

安装

目录结构

文件内容

public/index.html

src/index.js

src/components/app/app.jsx

src/components/comment-add/comment-add.jsx

src/components/comment-item/comment-item.jsx

src/components/comment-item/comment-item.css

src/components/comment-list/comment-list.jsx

src/components/comment-list/comment-list.css

redux/action-types.js

redux/actions.js

redux/reducers.js

redux/store.js

8.9 相关重要知识:纯函数和高阶函数

8.9.1 纯函数

  • 一类特别的函数:只要是同样的输入,必定得到同样的输出

    • 必须遵守以下一些约束

      • 不得改写参数

      • 不能调用系统 I/O 的 API

      • 能调用 Date.now() 或者 Math.random() 等不纯的方法

  • reducer函数必须是一个纯函数

8.9.2 高阶函数

  • 理解:一类特别的函数

    • 情况 1:参数是函数(回调函数)

    • 情况 2:返回是函数(新的函数)

  • 常见的高阶函数:

    • 定时器设置函数:setTimeout()/setInterval()

    • 数组的 map()/filter()/reduce()/find()/bind()

    • react-redux 中的 connect 函数

  • 作用:能实现更加动态,更加可扩展的功能

最后更新于