Redux Toolkit中如何存储Google Books API返回的多本收藏书籍
解决Redux Toolkit存储多本书籍时被覆盖的问题
我正在开发用户书签列表功能,使用Google Books API和Redux Toolkit,希望将API返回的书籍信息存入数组,用于展示用户添加到个人心愿单的书籍并进行相关操作。但目前状态中只能存储一本书籍,新添加的书籍会覆盖旧的,需要解决存储所有添加书籍的问题。
问题核心分析
当前代码的关键问题在于:
- Redux Slice的状态更新逻辑错误:
getBook.fulfilled中直接将state.list赋值为单本书籍对象,而非追加到数组中 - 组件中同时使用Redux dispatch和本地axios请求,逻辑冗余且状态管理混乱
步骤1:修正Redux Slice的状态更新逻辑
修改bookSlice.js,将新书籍追加到数组中,并添加去重逻辑避免重复存储:
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; import { BOOKS_BY_ID } from "../../services/api/googleBooks"; export const getBook = createAsyncThunk( "book/getBook", async ({ bookid }) => { const response = await fetch(`${BOOKS_BY_ID}${bookid}`); const data = await response.json(); return data; } ); // 可选:批量获取书籍的异步thunk,优化批量加载场景 export const getBooksByIds = createAsyncThunk( "book/getBooksByIds", async (bookIds) => { const requests = bookIds.map(id => fetch(`${BOOKS_BY_ID}${id}`).then(res => res.json())); const books = await Promise.all(requests); return books; } ); const bookSlice = createSlice({ name: "book", initialState: { list: [], status: null, }, reducers: {}, extraReducers: (builder) => { // 单个书籍请求处理 builder .addCase(getBook.pending, (state) => { state.status = "loading"; }) .addCase(getBook.fulfilled, (state, action) => { state.status = "success"; // 去重:检查是否已存在该书 const isExist = state.list.some(book => book.id === action.payload.id); if (!isExist) { state.list.push(action.payload); } }) .addCase(getBook.rejected, (state) => { state.status = "failed"; }) // 批量书籍请求处理(可选) .addCase(getBooksByIds.pending, (state) => { state.status = "loading"; }) .addCase(getBooksByIds.fulfilled, (state, action) => { state.status = "success"; // 批量去重后追加 const newBooks = action.payload.filter(newBook => !state.list.some(existingBook => existingBook.id === newBook.id) ); state.list.push(...newBooks); }) .addCase(getBooksByIds.rejected, (state) => { state.status = "failed"; }); }, }); export default bookSlice.reducer;
步骤2:优化组件请求逻辑
去掉冗余的本地axios请求,统一通过Redux管理状态:
import { useDispatch, useSelector } from 'react-redux'; import { getBooksByIds } from './bookSlice'; // ...组件其他逻辑 const dispatch = useDispatch(); // 从Redux store获取书籍列表 const bookList = useSelector(state => state.book.list); const status = useSelector(state => state.book.status); useEffect(() => { let ignore = false; if (bookInfos?.length > 0 && !ignore) { // 批量dispatch加载所有书签书籍 dispatch(getBooksByIds(bookInfos)); } return () => { ignore = true; }; }, [bookInfos, dispatch]); // 渲染时直接使用bookList return ( <div> {status === 'loading' && <div>加载中...</div>} {status === 'failed' && <div>加载失败</div>} {bookList.map(book => ( <div key={book.id}>{book.volumeInfo.title}</div> ))} </div> );
关键说明
- 状态更新方式:Redux Toolkit支持直接对state进行mutate操作(如
push),内部通过Immer自动转换为不可变更新;也可以使用扩展运算符[...state.list, action.payload]实现,两种方式均有效 - 去重逻辑:通过书籍
id判断是否已存在,可根据实际业务调整判断条件 - 批量请求优化:使用
Promise.all批量处理API请求,减少dispatch次数,提升加载性能
内容的提问来源于stack exchange,提问作者frontcodelover
相关产品推荐
相关产品推荐

