ReduxToolkit (RTK)
核心API
- configureStore: 包装createStore以提供简化的配置选项和良好的默认值。它可以自动组合你的 slice reducer,添加你提供的任何 Redux 中间件,redux-thunk默认包含,并启用 Redux DevTools Extension
- reducer 可以将slice中的reducer组成一个对象 传入此处
- middleware 可以使用除了默认 其他的中间件
- devTools 是否配置devTools工具 默认为true
- createSlice 接受reducer函数的对象、切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions。
- name :用户标记的slice名称(用于在redux- devtool中显示)
- initialState: 第一次初始化值
- reducers : 相当于之前的 reducer函数 他有两个参数
- state
- 调用这个action时 传递的action
- createSlice 返回的是一个对象 包含着所有actions
- createAsyncThunk :接受一个动作类型字符串和一个返回承诺的函数,并生成一个pending/fulfilled/rejected基于该承诺分派动作类型的thunk
- 第一个参数 为当前派发的名字
- 一个异步事件
-
当createAsyncThunk创建出来的action被dispatch时候 会有三种状态
- pending
- fulfilled
- rejected
-
可以在createSlice中的entraReducer的进行监听这三种结果
- 对象形式
extraReducers: {
[fetchHomeMultidataAction.pending](state, action) {
console.log("fetchHomeMultidataAction pending")
},
[fetchHomeMultidataAction.fulfilled](state, { payload }) {
state.banners = payload.data.banner.list
state.recommends = payload.data.recommend.list
},
[fetchHomeMultidataAction.rejected](state, action) {
console.log("fetchHomeMultidataAction rejected")
}
}
- 函数形式
extraReducers: (builder) => {
builder.addCase(fetchHomeMultidataAction.pending, (state, action) => {
console.log("fetchHomeMultidataAction pending")
}).addCase(fetchHomeMultidataAction.fulfilled, (state, { payload }) => {
state.banners = payload.data.banner.list
state.recommends = payload.data.recommend.list
})
}
- 也可以通过createAsyncThunk函数中 通过参数来调用stroe的dispatch
export const fetchHomeMultidataAction = createAsyncThunk(
"fetch/homemultidata",
async (extraInfo, { dispatch, getState }) => {
// console.log(extraInfo, dispatch, getState)
// 1.发送网络请求, 获取数据
const res = await axios.get("http://123.207.32.32:8000/home/multidata")
// 2.取出数据, 并且在此处直接dispatch操作(可以不做)
const banners = res.data.data.banner.list
const recommends = res.data.data.recommend.list
dispatch(changeBanners(banners))
dispatch(changeRecommends(recommends))
// 3.返回结果, 那么action状态会变成fulfilled状态
return res.data
})
关于React开发中 数据的不可变形 在Redux-Toolkit中如何实现的
在redux中的reducer函数中 需要返回一个新对象 这样在内部对比state进行比较是否修改的(浅比较) 但是在Redux-Toolkit中直接修改state就可以? 是这为什么呢?
在正常redux中的reducer
function reducer(state = defaultState, action) {
switch (action.type) {
case actionTypes.ADD_NUMBER:
return { ...state, counter: state.counter + action.num }
case actionTypes.SUB_NUMBER:
return { ...state, counter: state.counter - action.num }
default:
return state
}
}
在Redux-Toolkit中使用
reducers: {
changeBanners(state, { payload }) {
state.banners = payload
},
changeRecommends(state, { payload }) {
state.recommends = payload
}
},
}
在Redux-Toolkit中使用了immerjs库中的 利用了Persistent Data Structure(持久化数据结构或一致性 数据结构)算法
- 来进行数据结构的保存数据
- 当数据被修改时,会返回一个对象,但是新的对象会尽可能的利用之前的数据结构而不会 对内存造成浪费;
实现connect函数
connect函数 其实是通过高阶函数+高阶组件 组合形成的一种函数
- 实现1 :通过Provider传入app的store 从Context中获取到使用的store
- 实现2 : 组件内部设置state的默认值 通过subscribe来进行监听store中state如果变化 就使用setState修改组件内部state(内部会进行比较变化的key)然后更新组件
- 实现3 :映射传入的props和dispach 返回给组件props
StoreContext.js页面
import { createContext } from "react";
export const StoreContext = createContext()
// connect的参数:
// 参数一: 函数
// 参数二: 函数
// 返回值: 函数 => 高阶组件
import { PureComponent } from "react";
import { StoreContext } from "./StoreContext";
// import store from "../store"
export function connect(mapStateToProps, mapDispatchToProps, store) {
// 高阶组件: 函数
return function(WrapperComponent) {
class NewComponent extends PureComponent {
constructor(props, context) {
super(props)
this.state = mapStateToProps(context.getState())
}
componentDidMount() {
this.unsubscribe = this.context.subscribe(() => {
// this.forceUpdate()
this.setState(mapStateToProps(this.context.getState()))
})
}
componentWillUnmount() {
this.unsubscribe()
}
render() {
const stateObj = mapStateToProps(this.context.getState())
const dispatchObj = mapDispatchToProps(this.context.dispatch)
return <WrapperComponent {...this.props} {...stateObj} {...dispatchObj}/>
}
}
NewComponent.contextType = StoreContext
return NewComponent
}
}
实现中间件
- 实现一个log中间件 :每一次dispatch都需要打印对应信息
- 利用的是monkey patch候补丁 修改store中的dispatch的方法指向
function log(store) {
const next = store.dispatch
function logAndDispatch(action) {
console.log("当前派发的action:", action)
// 真正派发的代码: 使用之前的dispatch进行派发
next(action)
console.log("派发之后的结果:", store.getState())
}
// monkey patch: 猴补丁 => 篡改现有的代码, 对整体的执行逻辑进行修改
store.dispatch = logAndDispatch
}
log(store)
- 实现thunk中间件 ( 不仅仅dispatch对象 也可以处理函数)
- 根据判断action类型 如果是 function 则需要调用该函数 否则直接dispatch
function thunk(store) {
const next = store.dispatch
function dispatchThunk(action) {
if (typeof action === "function") {
action(store.dispatch, store.getState)
} else {
next(action)
}
}
store.dispatch = dispatchThunk
}
export default thunk
- 整合中间件 applyMiddleware文件 让他依次执行中间件
function applyMiddleware(store, ...fns) {
fns.forEach(fn => {
fn(store)
})
}
export default applyMiddleware
const store = createStore(reducer)
applyMiddleware(store, log, thunk)