Redux的整个工作流
1 用户(操作View) 发出action,发出方就用到了dispatch方法
2 然后,Store自动调用Reducer,并且传入两个参数(当前State和收到的Action), Reducer会返回新的State,如果有Middleware,Store会将当前State和收到的Action传递给Middleware, Middleware会调用Reducer然后返回新的State;
3 State一旦有变化,Store就会调用监听函数,来更新View
到这儿为止,一次用户交互流程结束.可以看到,在整个流程中数据都是单向流动的
Redux只有一个单一的store和一个根级的reduce函数(reducer), 随着应用的不断壮大,我们需要将根级的reducer拆分成多个小的reducers,分别独立地操作state树的不同部门,而不是添加新的stores
Redux的三个基本原则:
1 单一数据源: 整个应用的state被储存在一棵object tree中,并且这个object tree只存在于唯一一个store中
2 State是只读的,唯一改变state的方法就是触发action, action是一个用于描述已发生事件的普通对象
3 使用纯函数来执行修改: 为了描述action如何改变state tree, 你需要编写reducers
Redux有哪几部分构成?
1 action:action就是一个描述发生什么的对象
2 reducer:形式为(state,action) => state的纯函数,功能是根据action修改state 将其转变成下一个state
3 store: 用于存储state, 你可以把它看成一个容器,.整个应用只能有一个store
总结: Redux应用中所有的state都以一个对象树形式储存在一个单一的store中,唯一改变state的办法是触发action, action就是一个描述发生什么的对象.为了描述action如何改变state树, 你需要编写reducers.
action:
Action本质上是一个普通的javaScript对象,action内必须使用一个字符串类型的type字段来表示将要执行
的动作,除了type字段外,action对象的结构完全由你自己定义.多数情况下,type会被定义成字符串常量,当应用规模越来越大时候
建议使用单独的模块或者文件来存放action
Action创建函数
Action创建函数,就是生成action的方法. action和action创建函数这两个概念是不同的, 在Redux中的action创建函数只是简单的返回一个action
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
这样做将使action创建函数更容易被移植和测试
reducer:
reducer是根据action修改state将其转变成下一个state,记住actions只是描述了有事情发生了这一事实,并没有描述应用如何更新state
(previousState,aciton) => newState
保持reducer纯净非常重要,永远不要在reducer里做这些操作
1 修改传入参数
2 执行有副作用的操作,如API请求和路由跳转
3 调用非纯函数,如Date.now()或Math.random()
提示: reducer是纯函数,它仅仅作用于计算下一个state, 它应该是完全可预测的,多次传入相同的输入必须产生相同的输出, 它不应该有副作用的产出,如API调用或路由跳转, 这些应该在dispatch action前发生
合并和拆分reducer显得很重要, 这时候就要用到 combineReducers()这个函数了
Store
是存储state的容器, Store会把两个参数(当前的state树和action)传入reducer
store有以下职责:
1 维持应用的state
2 提供getState()方法获取state
3 提供dispatch(action)方法更新state,我们可以在任何地方调用store.dispatch(action). 包括组件中,XMLHttpRequest回调中,甚至定时器中
4 通过subscribe(listener) 注册监听器
5 通过subscribe(listener) 返回的函数注册监听器
在前一章中, 使用combineReducers()将多个reducer合并成为一个, 现在我们通过Redux的createStore()来创建一个Store
import {createStore} from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp)
高级:
异步Action:
对于网络请求 ,数据库加载等应用场景同步Action显然不适用, 对此我们需要用到异步Action
我们可以将异步Action简单理解为: 在Action中进行异步操作等操作返回后再dispatch一个action
使用异步aciton 需要引入redux-thunk库, redux-thunk是为Redux提供异步action支持的中间件
异步数据流:
默认情况下, createStore()所创建的Redux store没有使用middleware, 所以只支持同步数据流.
你可以使用applyModdleware() 来增强createStore().它可以帮助你用简便的方式来描述异步action.
像redux-thunk或redux-promise这样支持异步的middleware都包装了store的dispatch方法, 以此来
让你dispatch一些除了action以外的其他内容,例如: 函数或Promise, 你所使用的任何middleware都可以以自己
的方式解析你dispatch的任何内容. 并继续传递action给下一个middleware. 比如,支持Promise的middleware都能够
拦截Promise,然后为每个Promise异步地dispatch一对begin/end actions
注意: 当middleware链中的最后一个middleware开始dispatch action时, 这个action必须是一个普通对象
准备工作:
根据需要安装以下组件:
1 redux(必选)
2 react-redux(必选)
3 redux-devtools(可选) : Redux开发者工具 支持热加载,action重放,自定义UI等功能
4 redux-thunk:实现action异步的middleware
5 redux-persist(可选) : 支持store本地持久化
6 redux-observable(可选):实现可取消的action
视图层绑定引入了几个概念:
<Provider> 组件: 这个组件需要包裹在整个组件树的最外层. 这个组件让根组件的所有子孙组件能够轻松的使用connect()方法绑定store
connect() : 这是react-redux提供的一个方法, 如果一个组件想要响应状态的变化, 就把自己作为参数传给connect()的结果, connect()方法会处理与store绑定的细节,并通过selector确定该绑定store哪一部分的数据
selector: 这是你自己编写的一个函数, 这个函数声明了你的组件需要整个store中的哪一部分数据作为自己的props
dispatch: 每当你想要改变应用中的状态时, 你就要dispatch一个action, 这也是唯一改变状态的方法