一、Redux简介
1、作用
管理state
2、理念
为了让state的变化做到可追溯,不管是redux还是redux toolkit都是要求每个更改state的操作都要通过派发(despatch) action来实现。
-
action是一个JS对象
const addAction = { type: "ADD_SALARY", num: 2000 } const subAction = {type: "SUB_SALARY", num: 2000} -
那么一个action怎么能操作state的呢?——reducer(必须是纯函数,不能有副作用)
const initialState = { salary: 10000, } function reducer(state = initialState, action) { switch (action.type) { case "ADD_SALARY": // 为了避免副作用产生,需要重新创建一个对象,放入state属性,同时后面的属性将覆盖前面的属性 return {...state, salary: state.salary + action.num} case "SUB_SALARY":: return {...state, salary: state.salary - action.num} default: return state; } }- 随着应用变大,你可以reducer它拆成多个小的 reducers,分别独立地操作 state tree 的不同部分,因为 reducer 只是函数,你可以控制它们被调用的顺序,传入附加数据,甚至编写可复用的 reducer 来处理一些通用任务,如分页器。
function visibilityFilter(state = 'SHOW_ALL', action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
text: action.text,
completed: false
}
]
case 'COMPLETE_TODO':
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: true
})
}
return todo
})
default:
return state
}
}
import { combineReducers, createStore } from 'redux'
let reducer = combineReducers({ visibilityFilter, todos })
let store = createStore(reducer)
- reducer怎么知道何时执行了哪个action呢?——despatch方法,是redux通过
createStore()所创建的store对象中的方法。
import { createStore } from 'redux';
const store = createStore(reducer)
// 在派发之前监听store的变化
store.subscribe(() => {
console.log(store.getState())
})
// 派发actions
store.dispatch(ADD_SALARY);
store.dispatch(SUB_SALARY);
3、三大原则
单一数据源
整个应用程序的state被存储在一颗object tree中,并且这个object tree只存储在一个 store 中:
- Redux并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护;
- 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改;
State是只读的
唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
- 这样就确保了View或网络请求都不能直接修改state,相反它们只能表达想要修改的意图,它们只能通过action来描述自己想要如何修改state;
- 这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;
- Action 就是普通对象而已,因此它们可以被日志打印、序列化、储存、后期调试或测试时回放出来。
使用纯函数来执行修改
通过reducer将 state和 actions联系在一起,并且返回一个新的State:
- 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分;
- 但是所有的reducer都应该是纯函数,不能产生任何的副作用;
- 随着应用变大,你可以把它拆成多个小的 reducers,分别独立地操作 state tree 的不同部分,因为 reducer 只是函数,你可以控制它们被调用的顺序,传入附加数据,甚至编写可复用的 reducer 来处理一些通用任务,如分页器。
经过上面的介绍不难写出一个基本的redux使用逻辑代码
import { createStore } from 'redux';
const ADD_SALARY = "ADD_SALARY";
const ADD_NUMBER = "SUB_SALARY";
// 1.创建一个对象,作为状态
const initialState = {
salary: 0,
}
// 2. 创建reducer
// 当第一次调用reducer时,state为undefined则使用默认值initialState
const reducer = (state = initialState, action) => {
// 6.修改reducer中的代码
switch (action.type) {
case ADD_SALARY:
return {...state, salary: state.num + action.num};
case SUB_NUMBER:
return {...state, salary: state.num - action.num}
default:
return state;
}
}
// 3.创建store并传入reducer
const store = createStore(reducer)
// 7.在派发之前监听store的变化
store.subscribe(() => {
console.log(store.getState())
})
// 4.创建actions
const addAction = {type: ADD_SALARY, num: 2000}
const subAction = {type: SUB_SALARY, num: 2000}
// 5.分发actions
store.dispatch(addAction);
store.dispatch(subAction);
二、redux的基本使用
1、安装redux
yarn add redux
2、redux模块化
创建一个项目
yarn init
安装redux
yarn add redux
创建src目录,创建index.js
修改packge.json可以执行index.js,执行yarn start时相当于执行node src/index.js
"scripts": {
"start": "node src/index.js"
}
为了开发时代码更加规范,我们将store、reducer、action、constants拆开,而不是写在一起
创建store/index.js文件:
import redux from 'redux'
import reducer from './reducer.js'
const store = redux.createStore(reducer);
export default store;
创建store/reducer.js文件:
import {
ADD_NUMBER,
SUB_NUMBER
} from './constants.js'
const initialState = {
counter: 0,
}
function reducer(state = initialState, action) {
switch (action.type) {
case ADD_NUMBER:
return {...state, counter: state.counter + action.num}
case SUB_NUMBER:
return {...state, counter: state.counter - action.num}
default:
return state;
}
}
export default reducer;
创建store/actionCreators.js文件:
import {
ADD_NUMBER,
SUB_NUMBER
} from './constants.js'
const addAction = num => ({
type: ADD_NUMBER,
num
})
const subAction = num => ({
type: SUB_NUMBER,
num
})
export { addAction, subAction }
创建store/constants.js
export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";
在项目的index.js中进行测试
import store from './store/index.js'
import { addAction, subAction} from './store/actionCreators.js'
store.subscribe(() => {
console.log(store.getState())
})
store.dispatch(addAction(10))
store.dispatch(subAction(5))