import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/app/app'
ReactDOM.render(<App/>, document.getElementById('root'))
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + action.data
case 'DECREMENT':
return state - action.data
default:
return state
}
}
注意
返回一个新的状态
不要修改原来的状态
8.3.3 store
将 state、action 与 reducer 联系在一起的对象
如何得到此对象?
import {createStore} from 'redux'
import reducer from './reducers'
const store = createStore(reducer)
此对象的功能?
getState():得到 state
dispatch(action):分发 action,触发 reducer 调用,产生新的 state
import React from 'react'
import ReactDOM from 'react-dom'
import {createStore} from 'redux'
import App from './components/app'
import {counter} from './redux/reducers'
// 根据counter函数创建store对象
const store = createStore(counter) // 内部会第一次调用reduer函数,得到初始state
// 定义渲染根组件标签的函数
const render = () => {
ReactDOM.render(
<App store={store}/>,
document.getElementById('root')
)
}
// 初始化渲染
render()
// 注册(订阅)监听, 一旦状态发生改变, 自动重新渲染
store.subscribe(render)
也可以把 index.js 中 store 提取出来
src/redux/store.js
import {createStore} from 'redux'
import {counter} from './reducers'
// 根据counter函数创建store对象
const store = createStore(counter) // // 内部会第一次调用reduer函数,得到初始state
export default store
src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/app'
import store from './redux/store'
// 定义渲染根组件标签的函数
const render = () => {
ReactDOM.render(
<App store={store}/>,
document.getElementById('root')
)
}
// 初始化渲染
render()
// 注册(订阅)监听, 一旦状态发生改变, 自动重新渲染
store.subscribe(render)
问题
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数据
<Provider store={store}>
<App />
</Provider>
connect()
用于包装 UI 组件生成容器组件
import { connect } from 'react-redux'
connect(
mapStateToprops,
mapDispatchToProps
)(Counter)
mapStateToprops()
将外部的数据(即 state 对象)转换为 UI 组件的标签属性
const mapStateToprops = function (state) {
return {
value: state
}
}
title: React 教程之从概念到实战 date: 2020-07-12 16:54 updated: 2020-07-12 16:54 cover: //cdn.wallleap.cn/img/pic/cover/202302ihq49n.jpg category: 技术杂谈 tags:
前端 description: React 教程之从概念到实战
前端三大框架之一,用于构建用户界面的 JavaScript 库
一、React 入门
1.1 React 的基本认识
React 官网:
英文官网:https://reactjs.org/
中文官网:https://doc.react-china.org/
介绍描述:
React 是用于构建用户界面的 JavaScript 框架(只关注于 View)
JS 库&框架:
jQuery——函数库(方法、函数包装 DOM 操作)
React 基本上不操作 DOM——JS 框架
构建用户界面:把数据展现出来
由Facebook开源
React 的特点:
Declarative(声明式编码)
Component-Based(组件化编码)
Learn Once, Write Anywhere(支持客户端与服务器渲染)
高效
单向数据流
React 高效的原因(区域、次数——更新界面效率提高):
虚拟(virtual)DOM,不总是直接操作 DOM
DOM Diff 算法,最小化页面重绘
1.2 React 的基本使用
注意:此时只是测试语法使用, 并不是真实项目开发使用
实现效果:将 h1 标签利用 react 放到 test 中
相关的库:
react.js
:React 的核心库react-dom.js
:提供操作 DOM 的 React 扩展库babel.min.js
:解析 JSX 语法代码转为纯 JS 语法代码的库,这里不是 ES6 转 ES5(jsx 是 js 扩展语法)可以到 bootcdn 引用地址,访问链接 Ctrl + S 保存到本地
在页面中导入 js
开始编码
使用 React 开发者工具调试
React Developer Tool
1.3 React JSX
实现效果:两个
#test
分别加入相应内容代码:
虚拟 DOM
React 提供了一些 API 来创建一种 特别 的一般 js 对象
var element = React.createElement('h1', {id:'myTitle'}, 'hello')
虚拟 DOM 对象最终都会被 React 转换为真实的 DOM(虚拟 DOM 中的对应真实 DOM 中的标签元素)
我们编码时基本只需要操作 react 的虚拟 DOM 相关数据,react 会转换为真实 DOM 变化而更新界面
补充知识:
debugger
可以在某条 js 代码处添加断点虚拟 DOM——轻对象,更新虚拟 DOM 页面不重绘
真实 DOM——重对象,更新真实 DOM 页面会发生变化(页面重绘)
JSX
var ele = <h1>Hello JSX!</h1>
<
开头的代码, 以标签的语法解析:html 同名标签转换为 html 同名元素,其它标签需要特别解析{
开头的代码,以 JS 语法解析:标签中的 js 代码必须用{}
包含babel.js 的作用
type="text/babel"
,声明需要 babel 来处理渲染虚拟 DOM(元素)
ReactDOM.render(virtualDOM, containerDOM)
建虚拟 DOM 的 2 种方式
React.createElement('h1', {id:'myTitle'}, title)
<h1 id='myTitle'>{title}</h1>
JSX 练习:动态展示列表数据
代码:
1.4 模块与组件和模块化与组件化的理解
模块
有特定功能的 js 文件,内部有数据及对数据的操作
私有的函数向外暴露
组件
模块化
组件化
例如下面 App 组件就是一个组件,它又是由多个组件组成的
二、React 面向组件编程
面向对象 → 面向模块 → 面向组件
2.1 基本理解和使用
实现效果
组件标签:可以随便取的标签,首字母大写(与 HTML 标签区分开)
自定义组件(Component):
定义组件(2 种方式)
方式 1:工厂函数组件(简单组件:没有状态的组件)——效率高,不需要创建对象
方式 2:ES6 类组件(复杂组件)——需要创建对象,有了状态只能使用这种方式
渲染组件标签
注意
render()
渲染组件标签的基本流程2.2 组件三大属性 1:
state
实现效果
理解
state
是组件对象最重要的属性,值是对象(可以包含多个数据)state
来更新对应的页面显示(重新渲染组件)编码操作
初始化状态:
读取某个状态值
更新状态-->组件界面更新
实现代码
2.3 组件三大属性 2:
props
实现效果
理解
props
(properties 的简写)属性props
中作用
props
数据编码操作
内部读取某个属性值
this.props.propertyName
对
props
中的属性值进行类型限制和必要性限制扩展属性:将对象的所有属性通过
props
传递<Person {...person}/>
默认属性值
组件类的构造函数
代码
state
:组件自身内部可变化的数据props
:从组件外部向组件内部传递数据,组件内部只读不修改2.4 组件三大属性 3:
refs
与事件处理效果
refs
属性组件内的标签都可以定义
ref
属性来标识自己<input type="text" ref={input => this.msgInput = input}/>
回调函数在组件初始化渲染完或卸载时自动调用
在组件中可以通过
this.msgInput
来得到对应的真实 DOM 元素作用:通过
ref
获取组件内容特定标签对象,进行读取其相关数据事件处理
通过
onXxx
属性指定组件的事件处理函数(注意大小写)React 使用的是自定义(合成)事件, 而不是使用的原生 DOM 事件
React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
通过
event.target
得到发生事件的 DOM 元素对象强烈注意
this
为组件对象this
为null
this
:通过函数对象的bind()
/apply()
/call()
来指定this
this
,箭头函数内部的this
是上下文中的this
(箭头函数没有自己的this
,它的this
是外面的this
)代码
2.5 组件的组合
效果
功能界面的组件化编码流程(无比重要)
拆分组件:拆分界面,抽取组件
实现静态组件:使用组件实现静态页面效果(只有静态界面,没有动态数据和交互)
实现动态组件
实现初始化数据动态显示
实现交互功能(从绑定事件监听开始)
代码
2.6 收集表单数据
效果
理解
问题:在 react 应用中,如何收集表单输入数据
包含表单的组件分类
受控组件:表单项输入数据能自动收集成状态
非受控组件:需要时才手动读取表单输入框中的数据
代码
2.7 组件生命周期
效果
理解
组件对象从创建到死亡它会经历特定的生命周期阶段
React 组件对象包含一系列的勾子函数(生命周期回调函数),在生命周期特定时刻回调
在定义组件时,可以重写特定的生命周期回调函数,做特定的工作
生命周期流程图
Mount:挂载,将虚拟标签放到容器(页面)中
render() 渲染
左边初始化过程,这些方法称为声明周期回调函数,或称为生命周期的勾子,这些方法在特定的时刻调用
will 将、did 完成
生命周期详述
组件的三个生命周期状态:
Mount:插入真实 DOM
Update:被重新渲染
Unmount:被移出真实 DOM
React 为每个状态都提供了勾子(hook)函数,可重写
componentWillMount()
componentDidMount()
componentWillUpdate()
componentDidUpdate()
componentWillUnmount()
生命周期流程:
第一次初始化渲染显示:
ReactDOM.render()
constructor():创建对象初始化 state
componentWillMount():将要插入回调
render():用于插入虚拟 DOM 回调
componentDidMount():已经插入回调
每次更新 state:
this.setSate()
componentWillUpdate():将要更新回调
render():更新(重新渲染)
componentDidUpdate():已经更新回调
移除组件:
ReactDOM.unmountComponentAtNode(containerDom)
三个阶段,可以都打印一下,看下方法执行的过程(与写的顺序无关,但推荐按阶段的顺序写,更直观)
重要的勾子
render():初始化渲染或更新渲染调用
componentDidMount():开启监听,发送 ajax 请求
componentWillUnmount():做一些收尾工作,如清理定时器
componentWillReceiveProps():后面需要时讲
代码
2.8 虚拟 DOM 与 DOM Diff 算法
虚拟 DOM:减少操作真实 DOM 的次数,更新界面次数变少
DOM Diff 算法:计算哪里需要更新,哪里不需要更新,减少更新界面的区域
共同提高更新界面的效率
效果
只有时间更新,其他不更新
基本原理图
初始化:虚拟 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:3000
注:
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 start
或npm run start
3.2 demo:评论管理
效果
拆分组件
应用组件:App
添加评论组件:CommentAdd
state: username/string, content/string
props: add/func
评论列表组件:CommentList
评论项组件:CommentItem
实现静态组件
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
效果
4.2 axios
文档:
https://github.com/axios/axios
相关 API:
GET 请求
POST 请求
4.3 Fetch
文档
https://github.github.io/fetch/
https://segmentfault.com/a/1190000003810652
相关 API
GET 请求
POST 请求
4.4 demo:github 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 进行通信
这是以前的 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.props
、import {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 库
网址:https://github.com/ReactTraining/history
管理浏览器会话历史(history)的工具库
包装的是原生 BOM 中
window.history
和window.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){})
:监视历史记录的变化测试:
6.2 react-router 相关 API
react_router
web
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.html 已经详细讲过了match
对象:match 对象表示当前的路由地址是怎么跳转过来的withRouter
函数:当一个非路由组件也想访问到当前路由的 match,location,history 对象,那么 withRouter 将是一个非常好的选择6.3 基本路由使用
并没有刷新页面
准备
下载 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
总结:如何编写路由效果?
<NavLink></NavLink>
<Route></Route>
6.4 嵌套路由使用
嵌套路由——路由组件中的路由
二级路由组件:
views/news.jsx
二级路由组件:
views/message.jsx
一级路由组件:
views/home.jsx
6.5 向路由组件传递参数数据
传递的是 id 值
三级路由组件:
views/message-detail.jsx
二级路由组件:
views/message.jsx
路由链接与非路由链接:是否发了请求(路由连接不发)
<NavLink to=''></NavLink>
<Link to=''></Link>
<a href=''></a>
6.6 多种路由跳转方式
前面讲的路由切换都是通过点击链接的方式切换的,不是链接也能够
二级路由:
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(国外)
官网:http://www.material-ui.com/#/
GitHub:https://github.com/callemall/material-ui
7.1.2 ant-design(国内蚂蚁金服)
PC 官网:https://ant.design/index-cn
移动官网:https://mobile.ant.design/index-cn
Github:https://github.com/ant-design/ant-design/
Github:https://github.com/ant-design/ant-design-mobile/
7.2 ant-design-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 理解
学习文档
英文文档: https://redux.js.org/
中文文档: http://www.redux.org.cn/
Github: https://github.com/reactjs/redux
redux 是什么?
redux 是一个独立专门用于做状态管理的 JS 库(不是 react 插件库)
它可以用在 react、angular、vue 等项目中,但基本与 react 配合使用
作用:集中式管理 react 应用中多个组件共享的状态
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:数据属性,值类型任意,可选属性
例子:
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 编写应用
效果
使用 react 实现
下载依赖包
src/redux/action-types.js
src/redux/actions.js
src/redux/reducers.js
src/components/app.jsx
src/index.js
也可以把
index.js
中store
提取出来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 DevTools
下载工具依赖包
编码
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 函数
作用:能实现更加动态,更加可扩展的功能