Redux核心概念
action(需要做什么) reducer(处理器) store(数据仓库)
Reducer
前端需要一个独立的数据解决方案
Flux
Facebook提出的数据解决方案,它的最大历史意义,在于它引入了action的概念
action是一个普通的对象,用于描述要干什么。action是触发数据变化的唯一原因
store表示数据仓库,用于存储共享数据。还可以根据不同的action更改仓库中的数据
Redux
在Flux基础上,引入了reducer的概念
reducer:处理器,用于根据action来处理数据,处理后的数据会被仓库重新保存。
Reducer是用于改变数据的函数
- 一个数据仓库,有且仅有一个reducer,并且通常情况下,一个工程只有一个仓库,因此,一个系统只有一个reducer
- 为了方便管理,通常会将reducer放到单独的文件中
- reducer被调用的时机
- 通过store.dispatch(action),分发了一个action,此时,会调用reducer
- 当创建一个store的时候,会调用一次reducer
- 可以利用这一点,穿件仓库时,不传递默认状态,用reducer初始化状态,给reducer函数传参数state的时候给参数默认值
- reducer内部通常使用switch来判断type值
- reducer必须是一个没有副作用的纯函数
- 为什么是纯函数?
- 纯函数有利于测试和调试
- 有利于还原数据
- 有利于将来和react结合时的优化
- 具体要求
- 不能改变参数state,因此若要让状态变化,必须得到一个新的状态来return
- 不能有异步(ajx等)
- 不能对外部环境造成影响(locationStorage等等)
- 为什么是纯函数?
- 由于在大中型项目中,操作比较复杂,数据结构也比较复杂,因此,需要对reducer进行细分
- redux提供了方法,可以帮助我们更加方便的合并reducer
- combineReducers:合并reducer,得到一个新的reducer,该新的reducer管理一个对象,该reducer管理一个对象,该对象中的每一个属性交给对应的reducer管理
搭建结构
- action文件夹action-type
// action对象的type统一设置,symbol设置的值是唯一的
// users
export const ADDUSER = Symbol('add-user').toString()
export const DELETEUSER = Symbol('delete-user').toString()
export const UPDATEUSER = Symbol('update-user').toString()
// loginUser
export const SETLOGINUSER = Symbol('set-login--user').toString()
- action文件夹的user-action
import * as actionType from './action-type'
//约定action的格式:{type:'操作类型',payload:附加数据}
export default {
createAddUserAction: (user) => {
return { type: actionType.ADDUSER, payload: user }
},
createDeleteUserAction: (id) => {
return { type: actionType.DELETEUSER, payload: id }
},
createUpdateUserAction: (id, newUser) => {
return { type: actionType.UPDATEUSER, payload: { id, ...newUser } }
},
actionType,
}
- action文件夹的login-action
import * as actionType from './action-type'
//约定action的格式:{type:'操作类型',payload:附加数据}
export default {
createSetLoginAction: (loginUserData) => {
return { type: actionType.SETLOGINUSER, payload: loginUserData }
},
actionType,
}
- 细分的reducer
import userAction from '../../action/user-action'
import uuid from 'uuid'
const initialState = [
{ id: uuid(), name: '用户1', age: 11 },
{ id: uuid(), name: '用户2', age: 12 },
]
/**
* 细分的user的reducer
*/
export default (state = initialState, { type, payload }) => {
switch (type) {
case userAction.actionType.ADDUSER:
return [...state, payload]
case userAction.actionType.DELETEUSER:
return state.filter((it) => it !== it.payload)
case userAction.actionType.UPDATEUSER:
return state.map((it) =>
it.id === payload.id ? { ...it, ...payload } : it
)
default:
return state
}
}
import loginAction from '../../action/login-action'
const initialState = null
/**
* 细分的loginUser的reducer
*/
export default (state = initialState, { type, payload }) => {
switch (type) {
case loginAction.actionType.SETLOGINUSER:
return payload
default:
return state
}
}
- 合并的reducer
import LoginUserReducer from './subset/LoginUser'
import UserReducer from './subset/User'
import { combineReducers } from 'redux' //导入内置方法
// 手动实现合并多个细分的reducer
// export default function(state={},action){
// const newState={
// LoginUser:LoginUserReducer(state.LoginUser,action),
// User:UserReducer(state.User,action)
// }
// return newState
// }
// redux内置方法combineReducers直接合并多个reducer为一个的方法和上面的手写代码实现是一样的
export default combineReducers({
LoginUser: LoginUserReducer,
User: UserReducer,
})
- 使用仓库传入数据改变共享状态
import { legacy_createStore as createStore, bindActionCreators } from 'redux'
import userAction from './action/user-action'
import reducer from './reducer'
import uuid from 'uuid' //可以创建唯一id的js库
const store = createStore(reducer) //创建仓库
// store.dispatch(userAction.createAddUserAction({id:uuid(),name:'abc',age:10})) //该方法和下面实现一样
const bindAction = bindActionCreators(userAction, store.dispatch) //使用方法bindActionCreators将action方法集合和仓库的dispath方法传入
bindAction.createAddUserAction({ id: uuid(), name: 'abc', age: 10 }) //action方法直接调用更优雅
console.log(store.getState()) //得到仓库当前的数据
tionCreators将action方法集合和仓库的dispath方法传入
bindAction.createAddUserAction({ id: uuid(), name: 'abc', age: 10 }) //action方法直接调用更优雅
console.log(store.getState()) //得到仓库当前的数据