2013年 Facebook 提出了 Flux 架构的思想,引发了很多的实现。2015年,Redux 出现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构。Redux 由 Flux 演变而来,但受 Elm 的启发,避开了 Flux 的复杂性。
Redux 可以运行于不同的环境(客户端、服务器、原生应用),并且易于测试。Redux 在 Vue、Node、React 中都可以使用。 它体小精悍(只有2kB,包括依赖)。
需要使用Redux的项目:
从组件层面考虑,什么样子的需要 Redux:
Redux的设计思想:
注意:flux、redux 都不是必须和 react 搭配使用的,因为 flux 和 redux 是完整的架构,在学习 react 的时候,只是将 react 的组件作为 redux 中的视图层去使用了。
Redux 的使用的三大原则:
纯函数:
Reducer 函数最重要的特征是,它是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出
。Reducer不是只有Redux里才有,之前学的数组方法reduce, 它的第一个参数就是一个reducer。
纯函数是函数式编程的概念,必须遵守以下一些约束。
- 不得改写参数
- 不能调用系统 I/O 的API
- 不能调用 Date.now() 或者 Math.random() 等不纯的方法,因为每次会得到不一样的结果
由于 Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象,
说了这么多理论,都觉得有些枯燥了,下面我们来分析一个使用 redux 的简单案例:在 node 环境下通过 redux 实现对数字的加减操作。
首先在终端中执行下面的命令,安装 redux:
yarn add redux -S
index.js文件:
//解构出redux中的createStore方法
const {
createStore} = require('redux')
/**
* reducer是形式为(state,action)=>state 的纯函数
* 在reducer中对state设置默认值
* reducer的作用是通过判断action传过来的值,对数据进行操作
* 当state变化后,需要返回一个新的state,而不是修改传入的参数
**/
const reducer = (state = {
count: 1}, action) => {
switch (action.type) {
case "increment":
return {
count: state.count + 1
}
case "decrement":
return {
count: state.count - 1
}
default:
return state;
}
}
//使用createStore创建一个redux store,参数是reducer
//store里的方法有 dispatch subscribe getState replaceReducer
const store = createStore(reducer)
//手动订阅更新
store.subscribe(() => console.log(store.getState().count))
//派发事件
//改变内部state唯一的方法就是dispatch一个action
store.dispatch({
type: 'increment'}) //2
store.dispatch({
type: 'increment'}) //3
store.dispatch({
type: 'increment'}) //4
通过上面这个案例,我们来分析一下 redux 中几个要点:
总结:
项目中所有的 state 都以一个对象树的形式储存在一个唯一的 store 中。 改变 state 的唯一办法是把要做的修改变成一个普通对象,也就是 action。通过dispatch(action) 派发事件,在 reducer 函数中根据 action 传过来的内容操作 state,最后返回一个新的 state。通过 store.getState() 方法读取 state 里的数据。
1、store 通过 reducers 创建了初始状态;
2、页面加载时,view 通过 store.getState() 获取到 state 并挂载到自己的状态上;
3、当用户操作页面发生改变时,调用了 actions 的方法,创建了带有标识信息的 action ;
4、actions 将 action 通过调用 store.dispatch 方法发送到了reducer 中;
5、reducer 接收到 action 并根据标识信息对数据进行处理后,返回新的 state;
6、store 的 state 被 reducer 更改为新 state 的时候,store.subscribe 方法里的回调函数会执行,此时就可以通知 view 去重新获取 state;
Redux 和 React 之间没有关系。Redux 支持 React、Angular、Ember、jQuery 甚至纯 JavaScript。尽管如此,Redux 还是和 React 和 Deku 这类库搭配起来用最好,因为这类库允许你以 state 函数的形式来描述界面,Redux 通过 action 的形式来发起 state 变化。
react-redux 提供两个核心的api:
点击查看在react项目中如何使用 react-redux 实现一个简单的计数器功能
Redux 不支持多个 store。相反,只有一个单一的store
和一个根级的reduce函数(reducer
)。随着应用不断变大,你应该把根级的reducer
拆成多个小的 reducers
,分别独立地操作state
树的不同部分,而不是添加新的stores
。这就像一个 React 应用只有一个根级的组件,这个根组件又由很多小组件构成。
不同的业务模块有自己的reducers
,使用 combineReducers
方法将所有的reducer
整合到一起。
注意:
用法:
import {
combineReducers} from 'redux'
//IndexReducer可以作为一个模块导入进来,这里为了展示方便,都写在一个文件里
const IndexReducer=(state={
isShow:true},action)=>{
switch(action.type){
case "change_map_val":
return{
isShow:!state.isShow
}
default:
return state;
}
}
const reducer=combineReducers({
IndexReducer, //注意:在connect中读取值的时候,要使用state.IndexReducer
...
})
export default reducer
通常情况下,action 只是一个普通的对象,不能包含异步操作,这导致了很多创建 action 的逻辑只能写在组件中,代码量较多
也不便于复用
,组件的业务逻辑也不清晰
,使用异步中间件后,可以通过actionCreator
异步编写action
,这样代码就会拆分到 actionCreator
中,可维护性大大提高,可以方便于测试、复用,同时 actionCreator 还集成了异步操作中不同的 action 派发机制,减少编码过程中的代码量。
点击查看 Redux 异步库之 Redux-thunk 和 Redux-saga 的使用方法及区别