redux是什么
Redux 是一个独立的js状态管理库,非React内容之一
为什么要使用redux
Redux本身是MVVM渐进式框架,M(数据模型) - V(视图) - VM(虚拟模型)
核心概念
- state
- reducer
- store
- action
state对象
通常我们会把应用中的数据存储到一个对象树中 进行统一管理,我们把这个位置称为: state
state 是只读的
这里需要注意的是,为了保证数据状态的可维护性和测试,不推荐直接修改state中的原数据
通过纯函数修改 state
- 什么是纯函数
纯函数 – 函数式编程的一种概念
- 相同的输入永远返回相同的输出
- 不修改函数的输入值
- 不依赖外部环境状态
- 无任何副作用 (例如:异步请求以及定时器造成的问题)
使用纯函数的好处
- 便于测试
- 有利于重构
action 对象
-
我们对state 的修改是通过reducer 纯函数来进行的,同时通过传入的 action 来执行具体的操作
-
action 是一个对象
-
type 属性: 表示要进行操作的动作类型, 增删改查。。。。
-
payload属性: 操作 state 的同时传入的数据
-
但是这里需要注意的是,我们不直接去调用Reducer函数,而是通过Store对象提供的dispatch方法来调用
Store 对象 (负责存储的仓库)
- 为了对 state, reducer, action,进行统一的管理和维护,我们需要创建一个Store对象(仓库)
redus 三大原则
-
单一数据源: 整个应用的state 被储存在一棵 object tree中,并且这个object tree 只存在于唯一的store中
-
State 是只读的,唯一改变state的方法就是触发 action,action是一个用于描述已发生事件的普通对象
-
使用纯函数来进行修改
如何使用
1. 安装
npm i redux
2. 引入
import { createStore } from 'redux';
3. 创建一个仓库,参数为一个纯函数
let store = createStore(reducer);
4. reducer纯函数
因为state的值可读不可写,所以需要一个纯函数去修改内部的值
这里给state加了默认值,可以不加
function reducer(state = {
name: "电影院",
age: 20
}, action) {
return state;
};
输出仓库看浏览器反馈
console.log(store);
dispatch
dispatch: ƒ dispatch(action) —— 发起一次修改 (同步方法,立即执行)
action:{
type: "做了什么修改" --必填
}
getState
getState: ƒ getState() —— 获取状态
replaceReducer
replaceReducer: ƒ replaceReducer(nextReducer) —— 替换掉 reducer
subscribe
subscribe: ƒ subscribe(listener) —— 监听状态的修改
使用getState
console.log(store.getState());
浏览器反馈
使用dispatch
使用dispatch
发起1次
修改后在获取状态
function reducer(state = {
name: "电影院",
age: 20
}, action) {
// 不加这行注释的话,switch...case 会提示不是期望默认值,不过不影响,加不加无所谓
// eslint-disable-next-line
switch (action.type) {
case 'edit_name':
return {
...state,
name: action.name
}
}
return state;
};
...
store.dispatch({
type: "edit_name",
name: "健身房"
});
...
console.log(store.getState());
浏览器反馈
使用dispatch
发起2次
修改后在获取状态
function reducer(state = {
name: "电影院",
age: 20
}, action) {
// 不加这行注释的话,switch...case 会提示不是期望默认值,不过不影响,加不加无所谓
// eslint-disable-next-line
switch (action.type) {
case 'edit_name':
return {
...state,
name: action.name
};
case 'edit_age':
return {
...state,
age: action.age
};
}
return state;
};
...
store.dispatch({
type: "edit_name",
name: "健身房"
});
store.dispatch({
type: "edit_age",
age: 2100
});
...
console.log(store.getState());
浏览器反馈
使用dispatch
发起3次
修改且有一个是新属性
后在获取状态
function reducer(state = {
name: "电影院",
age: 20
}, action) {
// 不加这行注释的话,switch...case 会提示不是期望默认值,不过不影响,加不加无所谓
// eslint-disable-next-line
switch (action.type) {
case 'edit_name':
return {
...state,
name: action.name
};
case 'edit_age':
return {
...state,
age: action.age
};
case 'edit_time':
return {
...state,
time: action.time
}
}
return state;
};
...
store.dispatch({
type: "edit_name",
name: "健身房"
});
store.dispatch({
type: "edit_age",
age: 2100
});
store.dispatch({
type: "edit_time",
time: '待定'
});
...
console.log(store.getState());
浏览器反馈
使用subscribe
state发送改变时触发
- 参数为:出发时执行的回调函数
function reducer(state = {
name: "电影院",
age: 20
}, action) {
// 不加这行注释的话,switch...case 会提示不是期望默认值,不过不影响,加不加无所谓
// eslint-disable-next-line
switch (action.type) {
...
}
return state;
};
store.subscribe(()=>{
console.log(store.getState());
});
store.dispatch({
...
});
浏览器反馈
combineReducers
我们上边已经使用了dispatch发起修改成功了,但是可以看出代码量是很多的,而且很庞大。
所以我们换一种写法
import React from 'react';
import { createStore, combineReducers } from 'redux';
function index(state = { name: "首页" }, action) {
// eslint-disable-next-line
switch (action.type) {
case 'edit_name':
return {
...state,
name: action.name
}
}
return state
}
function list(state = { age: 20, time: "信息" }, action) {
// eslint-disable-next-line
switch (action.type) {
case 'edit_age':
return {
...state,
age: action.age
}
case 'edit_time':
return {
...state,
time: action.time
}
}
return state
}
function reducer(state = {}, action) {
return {
index: index(state.index, action),
list: list(state.list, action)
}
}
let store = createStore(reducer);
store.subscribe(() => {
console.log(store.getState())
})
store.dispatch({
type: "edit_name",
name: "哈哈哈"
})
store.dispatch({
type: "edit_age",
age: 2100
})
store.dispatch({
type: "edit_time",
time: "待定"
})
function App() {
return (<div>
123
</div>)
}
export default App
浏览器反馈
但是这里还没有更简洁,可以把reducer
这个函数换成下边这种写法
let reducer = combineReducers({
index,
list
});
参数: 传入一个对象,这个对象的属性中,就是要合并的reducer
注意点: 对象的属性名,要和函数名相同
浏览器反馈