API 简化
API 简化
Store Setup
标准的
import { applyMiddleware, createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import thunkMiddleware from "redux-thunk";
import monitorReducersEnhancer from "./enhancers/monitorReducers";
import loggerMiddleware from "./middleware/logger";
import rootReducer from "./reducers";
export default function configureStore(preloadedState) {
const middlewares = [loggerMiddleware, thunkMiddleware];
const middlewareEnhancer = applyMiddleware(...middlewares);
const enhancers = [middlewareEnhancer, monitorReducersEnhancer];
const composedEnhancers = composeWithDevTools(...enhancers);
const store = createStore(rootReducer, preloadedState, composedEnhancers);
if (process.env.NODE_ENV !== "production" && module.hot) {
module.hot.accept("./reducers", () => store.replaceReducer(rootReducer));
}
return store;
}
- 拥有一个带有 “命名 “参数的选项对象,它可以更容易读取。
- 让你提供你想添加到
Store 的中间件和增强器的数组,并自动为你调用applyMiddleware 和compose 。 - 自动启用
Redux DevTools 扩展。
此外,
redux-thunk 是最常用的中间件,用于处理组件之外的同步和异步逻辑。- 在开发中,检查常见错误的中间件,如
Mutation 状态或使用不可序列化的值。
这意味着
import { configureStore } from "@reduxjs/toolkit";
import rootReducer from "./reducers";
const store = configureStore({
reducer: rootReducer,
});
export default store;
如果你需要自定义
import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
import monitorReducersEnhancer from "./enhancers/monitorReducers";
import loggerMiddleware from "./middleware/logger";
import rootReducer from "./reducers";
export default function configureAppStore(preloadedState) {
const store = configureStore({
reducer: rootReducer,
middleware: [loggerMiddleware, ...getDefaultMiddleware()],
preloadedState,
enhancers: [monitorReducersEnhancer],
});
if (process.env.NODE_ENV !== "production" && module.hot) {
module.hot.accept("./reducers", () => store.replaceReducer(rootReducer));
}
return store;
}
如果你提供了中间件参数,
Writing Reducers
由于
function todosReducer(state = [], action) {
switch (action.type) {
case "ADD_TODO": {
return state.concat(action.payload);
}
case "TOGGLE_TODO": {
const { index } = action.payload;
return state.map((todo, i) => {
if (i !== index) return todo;
return {
...todo,
completed: !todo.completed,
};
});
}
case "REMOVE_TODO": {
return state.filter((todo, i) => i !== action.payload.index);
}
default:
return state;
}
}
通过
const todosReducer = createReducer([], {
ADD_TODO: (state, action) => {
// "mutate" the array by calling push()
state.push(action.payload);
},
TOGGLE_TODO: (state, action) => {
const todo = state[action.payload.index];
// "mutate" the object by overwriting a field
todo.completed = !todo.completed;
},
REMOVE_TODO: (state, action) => {
// Can still return an immutably-updated value if we want to
return state.filter((todo, i) => i !== action.payload.index);
},
});
当试图更新深度嵌套的状态时
case "UPDATE_VALUE":
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
可以简化为只:
updateValue(state, action) {
const {someId, someValue} = action.payload;
state.first.second[someId].fourth = someValue;
}
在现代
const keyName = "ADD_TODO4";
const reducerObject = {
// Explicit quotes for the key name, arrow function for the reducer
"ADD_TODO1" : (state, action) => { }
// Bare key with no quotes, function keyword
ADD_TODO2 : function(state, action){ }
// Object literal function shorthand
ADD_TODO3(state, action) { }
// Computed property
[keyName] : (state, action) => { }
}
Action Creators
const actionCreator = createAction("SOME_ACTION_TYPE");
const reducer = (state = {}, action) => {
switch (action.type) {
// ERROR: this won't work correctly!
case actionCreator: {
break;
}
// CORRECT: this will work as expected
case actionCreator.toString(): {
break;
}
// CORRECT: this will also work right
case actionCreator.type: {
break;
}
}
};
createSlice
import { combineReducers } from "redux";
import usersReducer from "./usersReducer";
import postsReducer from "./postsReducer";
const rootReducer = combineReducers({
users: usersReducer,
posts: postsReducer,
});
常见的方法是在自己的文件中定义片的
// postsConstants.js
const CREATE_POST = "CREATE_POST";
const UPDATE_POST = "UPDATE_POST";
const DELETE_POST = "DELETE_POST";
// postsActions.js
import { CREATE_POST, UPDATE_POST, DELETE_POST } from "./postConstants";
export function addPost(id, title) {
return {
type: CREATE_POST,
payload: { id, title },
};
}
// postsReducer.js
import { CREATE_POST, UPDATE_POST, DELETE_POST } from "./postConstants";
const initialState = [];
export default function postsReducer(state = initialState, action) {
switch (action.type) {
case CREATE_POST: {
// omit implementation
}
default:
return state;
}
}
鸭子文件结构建议将给定分片的所有
// postsDuck.js
const CREATE_POST = "CREATE_POST";
const UPDATE_POST = "UPDATE_POST";
const DELETE_POST = "DELETE_POST";
export function addPost(id, title) {
return {
type: CREATE_POST,
payload: { id, title },
};
}
const initialState = [];
export default function postsReducer(state = initialState, action) {
switch (action.type) {
case CREATE_POST: {
// Omit actual code
break;
}
default:
return state;
}
}
这简化了处理流程,因为我们不需要多个文件,而且我们可以去掉多余的动作类型常量的导入。但是,我们仍然必须手工编写动作类型和
const postsSlice = createSlice({
name: "posts",
initialState: [],
reducers: {
createPost(state, action) {},
updatePost(state, action) {},
deletePost(state, action) {},
},
});
console.log(postsSlice);
/*
{
name: 'posts',
actions : {
createPost,
updatePost,
deletePost,
},
reducer
}
*/
const { createPost } = postsSlice.actions;
console.log(createPost({ id: 123, title: "Hello World" }));
// {type : "posts/createPost", payload : {id : 123, title : "Hello World"}}
大多数情况下,您会希望定义一个切片,并导出它的动作创建者和还原者。推荐的方法是使用
const postsSlice = createSlice({
name: "posts",
initialState: [],
reducers: {
createPost(state, action) {},
updatePost(state, action) {},
deletePost(state, action) {},
},
});
// Extract the action creators object and the reducer
const { actions, reducer } = postsSlice;
// Extract and export each action creator by name
export const { createPost, updatePost, deletePost } = actions;
// Export the reducer, either as a default or named export
export default reducer;