Redux
官方链接https://www.redux.org.cn/
Redux 是一个独立的JavaScript 状态管理库,不属于React内容。
Redux 本身是 MVVM渐进式框架 M(数据模型) - V(视图) - VM(虚拟模型)
定义: 官方定义,是 JavaScript 状态容器,提供可预测化的状态管理。
作用及特点:
- 可以构建一致化的应用,
- 运行于不同的环境(客户端、服务器、原生应用),
- 易于测试
- 提供超爽的开发体验,比如有一个时间旅行调试器可以编辑后实时预览。
- 除了与React一起用之外,还支持其它界面库。
- 体小精悍(只有2kB,包括依赖)。
Redux 三大原则
- 单一数据源: 整个应用的state 被储存在一棵对象树中,并且这个对象只存在于唯一的store中
- State 是只读的,通过触发 action去改变state(唯一方法),action是一个用于描述已发生事件的普通对象
- 使用纯函数来进行修改
使用之前先安装(通过npm来安装)
npm i --save redux
store
负责存储的仓库
,是一个对象。
为了对 state, reducer, action,进行统一的管理和维护,
我们需要创建一个Store对象(仓库)
import {createStore} from 'redux';
// createStore()创建一个仓库,仓库存储state,reducer管理员管理state
// 注意该方法中传入reducer函数体,不是函数的调用
let store = createStore(reducer);
console.log(store);
store对象提供的方法:
/*
* dispatch(action):发起一次修改(同步方法,会立即执行)
* --参数action
* action:{type:"做了什么修改"}
*
* subscribe(listener):监听状态的修改(每次state有修改,都会监听)
* getState():获取状态
* replaceReducer(nextReducer):替换掉reducer(不常用)
*
*/
state
数据存储到一个对象树中进行统一管理的位置成为state
注意
:为了保证数据状态的可维护性和测试,不推荐直接修改state中的原数据,state是只读的。
修改 state
我们通过纯函数
来对state修改,什么是纯函数?
纯函数是函数式编程的一种概念。
function reducer(state=默认值,action){return xx;}
第一个参数(必需):state的初始值(数据)
第二个参数(必需):action修改了什么
return 返回值(必需)
纯函数特点如下:
- 相同的输入永远返回相同的输出
- 不修改函数的输入值
- 不依赖外部环境状态
- 无任何副作用 (如:异步请求以及定时器造成的问题)
使用纯函数的好处:
- 便于测试
- 有利于重构
reducer
reducer如同管理员,去管理store仓库中存储的state
function reducer(state={
name:"React从初级到精通",
price:59
},action){
//action是dispatch方法传过来的对象(即修改后的值返回的新对象)
// switch做分类判断
switch (action.type) {
// 修改的name
case 'new-name':
// 当 state 变化时需要返回全新的对象,而不是修改传入的参数。
return {
// 解构state
...state,
// name的新值
name:action.name
}
// 修改的price
case 'new-price':
return {
...state,
price:action.price
}
}
return state;
}
action
通过reducer 纯函数来进行对state修改,同时通过传入的 action 来执行具体的操作
- action 是一个对象
- type 属性: 表示要进行操作的动作类型,如增删改查操作
- payload属性: 操作 state 的同时传入的数据
注意
:我们不直接去调用Reducer函数,而是通过Store对象提供的dispatch方法来调用
// 监听state状态
// 每次state修改都会触发该监听方法
store.subscribe(()=>{
console.log(store.getState())
});
// 修改state状态
// 修改name
store.dispatch({
type:"new-name",
name:"HTML5全栈之路"
});
// 修改price
store.dispatch({
type:"new-price",
price:49
});
完整示例:
import React from 'react';
import {createStore} from 'redux';
function reducer(state={
// 首页数据
index:{name:"首页数据"},
// 留言数据
message:{name:"留言数据"},
// 列表数据
list:{name:"列表数据"}
},action){
switch (action.type) {
case "index":
return {...state,index:action.index.name}
case "message":
return {...state,message:action.message.name}
case "list":
return {...state,list:action.list.name}
}
return state;
}
let store = createStore(reducer);
store.dispatch({
type:"index_info",
name:"首页"
})
store.dispatch({
type:"message_info",
name:"留言"
})
store.dispatch({
type:"list_info",
name:"列表"
})
function App() {
return (
<div className="App">
<h2>hello,good morning</h2>
</div>
);
}
export default App;
从上例中,我们看到如果有多个页面需要管理时,都放在一个仓库中,一个管理员去管理时,
代码会显得很臃肿不清晰,还有别的办法可以处理吗?
当然有,我们可以将它们分别封装成函数,使用Redux提供combineRuders方法统一调用。
修改如下:
import {createStore,combineRuders} from 'redux';
//分别封装成函数,分别管理,相当于使用分管理员去管理,最后再主管理员reducer通过分管理员去统一管理
function index(state={info:"首页"},action){
switch (action.type) {
case "index_info":
return {
...state,
index:action.info
}
}
return state;
}
function message(state={info:"留言"},action){
switch (action.type) {
case "message_info":
return {
...state,
message:action.info
}
}
return state;
}
function list(state={info:"列表"},action){
switch (action.type) {
case "list_info":
return {
...state,
list:action.info
}
}
return state;
}
// 手动合并
//function reducer(state={},action){
// return {
// index:index(state.index,action),
// message:message(state.message,action),
// list:list(state.list,action)
// }
//}
// 使用Redux提供的combineReducers()方法来合并
let reducer = combineReducers({
// 给该方法传入一个对象作为参数,这个对象的属性就是要合并的reducer,
// 对象的属性名:函数名
// 这里的对象的属性名与函数名一致,只写一个就可以
index,
message,
list
});
// 创建仓库
let store = createStore(reducer);
// 监听state
store.subscribe(()=>{
console.log(store.getState());
});
// 修改state
store.dispatch({
type:"index_info",
info:"我是首页内容"
});
store.dispatch({
type:"message_info",
info:"我是留言内容"
});
store.dispatch({
type:"list_info",
info:"我是列表内容"
});
如图,store的subscribe()方法在每次state修改时都会去监听,控制台输出了每次监听到的修改的结果。