在 Redux 学习笔记笔记中我们已经对 Redux 有了一个大概的认识,接下来我们来链接一下Redux Tookit
这个工具包。
在编写 Redux 的代码时,我们会编写很多的模块代码和业务逻辑代码,在编写过程中比较的繁琐,而Redux Tookit
工具包可以简化 Redux 的开发步骤。
首先我们先回顾一下以前是用 Redux 编写代码的过程,具体有如下的几个步骤:
创建Actions
里面还有业务名称和对应函数传入的参数
创建Reducers
Reducers
通过 switch
语句来维护对应的 Action 和相应的业务处理,并且维护对应的State
数据。
使用Store
来关联Actions
和Reducers
以上就是使用 Redux 编写代码的过程,而createSlice
API 为我们做了几件重要的事情:
具体的实例代码如下:
const createSlice = require("@reduxjs/toolkit").createSlice;
const initialState = {
numOfIcecreams: 10,
};
const icecreamSlice = createSlice({
name: "icecream",
initialState,
reducers: {
ordered: (state) => {
state.numOfIcecreams--;
},
restocked: (state, action) => {
state.numOfIcecreams += action.payload;
},
},
extraReducers: (builder) => {
builder.addCase(cakeActions.ordered, (state) => {
state.numOfIcecreams--;
});
},
});
// 对外暴露相应的执行动作
module.exports = icecreamSlice.reducer;
module.exports.icecreamActions = icecreamSlice.actions;
使用createSlice
API 我们只能实现 Redux reducer 和 actions,而最重要的 Store 并未实现。而使用 Tookit 来实现 Store 的很简单,具体的实例如下:
const configureStore = require("@reduxjs/toolkit").configureStore;
const cakeReducer = require("../features/cake/cakeSlice");
// 假如有多个Reducer的话都可以直接在这里声明
const store = configureStore({
reducer: {
cake: cakeReducer,
},
});
调用 Store 的实例如下:
const store = require("./app/store");
const icecreamActions =
require("./features/icecream/icecreamSlice").icecreamActions;
console.log("Initial State ", store.getState());
const unsubscribe = store.subscribe(() => {
console.log("Updated State ", store.getState());
});
store.dispatch(cakeActions.ordered());
store.dispatch(cakeActions.ordered());
store.dispatch(cakeActions.ordered());
store.dispatch(cakeActions.restocked(3));
使用 Tookit 来声明中间件其实很简单,就比如我们使用redux-logger
中间件为例,我们首先安装redux-logger
中间件,然后在 Store 中进行声明。具体的实例如下:
const reduxLogger = require('redux-logger')
const logger = reduxLogger.createLogger()
const store = configureStore({
reducer: {
cake: cakeReducer,
}
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(logger)
})
module.exports = store
额外的 Reducer 主要是可以让同一个 slice reducer 监听其他 action types。
就比如一个商店中可以卖蛋糕和冰淇淋,但是随着业务的增长,顾客买了一个蛋糕我们就会送一个冰淇淋。这样当我们的蛋糕减一的时候,冰淇淋也会随着减一,我们就可以使用额外的 Reducer 来实现这个业务。
具体实现步骤如下:
const createSlice = require("@reduxjs/toolkit").createSlice;
const initialState = {
numOfCakes: 20,
};
const cakeSlice = createSlice({
name: "cake",
initialState,
reducers: {
ordered: (state) => {
state.numOfCakes--;
},
restocked: (state, action) => {
state.numOfCakes += action.payload;
},
},
});
module.exports = cakeSlice.reducer;
module.exports.cakeActions = cakeSlice.actions;
const { cakeActions } = require("../cake/cakeSlice");
const createSlice = require("@reduxjs/toolkit").createSlice;
const initialState = {
numOfIcecreams: 10,
};
const icecreamSlice = createSlice({
name: "icecream",
initialState,
reducers: {
ordered: (state) => {
state.numOfIcecreams--;
},
restocked: (state, action) => {
state.numOfIcecreams += action.payload;
},
},
// 声明一个而外的Reducer,当蛋糕执行ordered的时候,冰淇淋就会减一
extraReducers: (builder) => {
builder.addCase(cakeActions.ordered, (state) => {
state.numOfIcecreams--;
});
},
});
module.exports = icecreamSlice.reducer;
module.exports.icecreamActions = icecreamSlice.actions;
使用 Tookit 实现异步也有对应的 API 函数可以使用,具体可以使用createAsyncThunk
。
此 API 功能函数主要接受两个参数:
操作名称
将用作生成的 action 类型的前缀的字符串,用于后续声明调用
异步回调函数
执行异步后返回异步结果的回调函数
createAsyncThunk
它会根据返回的值自动分配生命周期操作的 Promise 对应的状态值,并可以使用 rducer 函数监听这些操作类型并执行必要的状态转换。
使用createAsyncThunk
创建出来的操作可以通过dispatch
来调用,也可以在而外的 Reducer 中声明使用,具体的实例如下:
const axios = require("axios");
const createSlice = require("@reduxjs/toolkit").createSlice;
const createAsyncThunk = require("@reduxjs/toolkit").createAsyncThunk;
const initialState = {
loading: false,
users: [],
error: "",
};
const fetchUsers = createAsyncThunk("user/fetchUsers", () => {
return axios
.get("https://jsonplaceholders.typicode.com/users")
.then((response) => response.data.map((user) => user.id));
});
const userSlice = createSlice({
name: "user",
initialState,
extraReducers: (builder) => {
builder.addCase(fetchUsers.pending, (state) => {
state.loading = true;
});
builder.addCase(fetchUsers.fulfilled, (state, action) => {
state.loading = false;
state.users = action.payload;
state.error = "";
});
builder.addCase(fetchUsers.rejected, (state, action) => {
state.loading = false;
state.users = [];
state.error = action.error.message;
});
},
});
module.exports = userSlice.reducer;
module.exports.fetchUsers = fetchUsers;
调用异步函数
const fetchUsers = require("./features/user/userSlice").fetchUsers;
store.dispatch(fetchUsers());