You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux Toolkit中如何存储Google Books API返回的多本收藏书籍

解决Redux Toolkit存储多本书籍时被覆盖的问题

我正在开发用户书签列表功能,使用Google Books API和Redux Toolkit,希望将API返回的书籍信息存入数组,用于展示用户添加到个人心愿单的书籍并进行相关操作。但目前状态中只能存储一本书籍,新添加的书籍会覆盖旧的,需要解决存储所有添加书籍的问题。

问题核心分析

当前代码的关键问题在于:

  1. Redux Slice的状态更新逻辑错误:getBook.fulfilled中直接将state.list赋值为单本书籍对象,而非追加到数组中
  2. 组件中同时使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 20:00:36