1.什么是Redux?
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。 (如果你需要一个 WordPress 框架,请查看 Redux Framework。)
可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。不仅于此,它还提供 超爽的开发体验,比如有一个时间旅行调试器可以编辑后实时预览。
Redux 除了和 React 一起用外,还支持其它界面库。 它体小精悍(只有2kB,包括依赖)。
redux 中文介绍:http://www.redux.org.cn/
2.Redux的基本原则
单向数据流
ui –> action – > store –> reducer –> store –> ui
唯一数据源
整个应用的状态被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中
保持状态只读
唯一改变 状态 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
数据的改变只能通过纯函数完成
描述 action 如何改变 状态树 ,需要编写 reducer。reducer 是一些纯函数, 负者更新状态树
3.Redux 的三大部分
1.Store
Store 是存整个应用状态的对象。因为所有的状态都存在Store上,所以Store的状态树设计非常重要,它直接决定了下面的reducer和action怎么写,也是程序逻辑的源头。
例如 , 官网todos案例的Store的状态树设计:
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
id:1
text: 'Consider using Redux',
completed: true,
},
{
id:2
text: 'Keep all state in a single tree',
completed: false
}
]
}
2.Action
Action 是把数据从应用(译者注:这里之所以不叫 view 是因为这些数据有可能是服务器响应,用户输入或其它非 view 的数据 )传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过
store.dispatch()
将 action 传到 store交给 reducer处理 。
例如 , 定义一个Action
export const removeTodo = (id) => ({
type: "REMOVE_TODO",
id: id
});
//or
export const removeTodo=(id)=>{
return{
type: "REMOVE_TODO",
id: id
}
}
3.Reducer
reducer 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。而Reducer是存函数专门用来描述如何更新state。
例如, 定义一个reducer
export default (state = [], action) => {
switch(action.type) {
//...
case "REMOVE_TODO": {
return state.filter((todoItem) => {
return todoItem.id !== action.id;
})
}
default:
return state;
}
}
4.Redux 的简单使用案例
1.使用npm新建一个项目
npm init -y //进入某一个文件夹打开cmd执行,例如进入本地的:redux-demo文件夹
npm install redux@3.7.2 --save //在redux-demo项目中安装redux
redux-demo文件夹如下图:
2.编写action
在redux-demo文件夹下新建一个sample.js文件,在sample.js文件中编写代码
/*==================action=====================*/
/**
定义一个加法的action;
每一个action返回的是一个对象,对象必须包含type属性
*/
var add=(number)=>{
return{
type:'add',
number:number,
}
}
/**
*定义一个减法的 action
*
*/
var sub=(number)=>{
return{
type:'sub',
number:number,
}
}
/*==================reducer=====================*/
/*==================store=====================*/
/*==================简单使用====================*/
3.编写reducer
在sample.js文件中编写代码
/*==================action=====================*/
/*==================reducer=====================*/
/**
* 定义一个reducer函数
* @param state store对象中的状态树:例如下面的:{ num : xx }
* @param action 用户触发的action动作;例如上面的:{ type:'add',number:xxx }
*/
var reducer=(state,action)=>{
var {number,type}=action;
switch (type){
case 'add':
/*Object.assign()对象的拷贝*/
return Object.assign({},state,{num:state.num+number,});
case 'sub':
return Object.assign({},state,{num:state.num-number,});
default:
return state;
}
}
/*==================store=====================*/
/*==================简单使用====================*/
4.编写store
在sample.js文件中编写代码
/*==================action=====================*/
/*==================reducer=====================*/
/*==================store=====================*/
/**ES5语法导入redux*/
var redux=require('redux');
/**
* 初始化状态树
* */
var initValue={
num:0,
}
/**
* 调用redux中的createStore获取到store对象
* */
var store =redux.createStore(reducer,initValue);
/*==================简单使用====================*/
5.测试分发事件
在sample.js文件中编写代码
/*==================action=====================*/
/**
定义一个加法的action;
每一个action返回的是一个对象,对象必须包含type属性
*/
var add=(number)=>{
return{
type:'add',
number:number,
}
}
/**
*定义一个减法的 action
*
*/
var sub=(number)=>{
return{
type:'sub',
number:number,
}
}
/*==================reducer=====================*/
/**
* 定义一个reducer函数
* @param state store对象中的状态树:例如下面的:{ num : xx }
* @param action 用户触发的action动作;例如上面的:{ type:'add',number:xxx }
*/
var reducer=(state,action)=>{
var {number,type}=action;
switch (type){
case 'add':
return Object.assign({},state,{num:state.num+number,});
case 'sub':
return Object.assign({},state,{num:state.num-number,});
default:
return state;
}
}
/*==================store=====================*/
/**ES5语法导入redux*/
var redux=require('redux');
/**
* 初始化状态树
* */
var initValue={
num:0,
}
/**
* 获取到store对象
* */
var store =redux.createStore(reducer,initValue);
/*==================简单使用====================*/
console.log('初始化的状态树:',store.getState()); // 0
/*1.分发一个 add 事件*/
store.dispatch(add(10) );
console.log('+10后的状态树:',store.getState()); //10
/*2.分发一个 sub 事件*/
store.dispatch(sub(1) );
console.log('-1后的状态树:',store.getState()); //9
右击执行sample.js文件控制台输出:
初始化的状态树: { num: 0 }
+10后的状态树: { num: 10 }
-1后的状态树: { num: 9 }
6.监听状态树的更新
/*==================action=====================*/
/*==================reducer=====================*/
/*==================store=====================*/
/*==================简单使用====================*/
var onChange=()=>{
console.log('监听状态树的更新',store.getState()); //9
}
/*监听状态树的更新*/
store.subscribe(onChange);
/*1.分发一个 add 事件*/
store.dispatch(add(10) );
/*2.分发一个 sub 事件*/
store.dispatch(sub(1) );
/*3.分发一个 sub 事件*/
store.dispatch(sub(3) );
右击执行sample.js文件控制台输出:
监听状态树的更新 { num: 10 }
监听状态树的更新 { num: 9 }
监听状态树的更新 { num: 6 }
7.取消监听状态树的更新
/*==================action=====================*/
/*==================reducer=====================*/
/*==================store=====================*/
/*==================简单使用====================*/
var onChange=()=>{
console.log('监听状态树的更新',store.getState()); //9
}
/*监听状态树的更新*/
var unsubscribe=store.subscribe(onChange);
/*1.分发一个 add 事件*/
store.dispatch(add(10) );
/*2.分发一个 sub 事件*/
store.dispatch(sub(1) );
/*取消监听状态树的更新*/
unsubscribe();
/*3.分发一个 sub 事件*/
store.dispatch(sub(3) );
右击执行sample.js文件控制台输出:
监听状态树的更新 { num: 10 }
监听状态树的更新 { num: 9 }