从 createAsyncThunk 获取的数据未定义

问题描述 投票:0回答:1

我想在浏览器第一次运行时显示位于服务器文件夹中的文件 db.json 中的所有书籍。我正在使用 json-server 来做到这一点。但是,我在 HomePage.js 中发现了错误 Uncaught TypeError:无法读取未定义的属性(读取“书籍”)。我尝试查看 bookListSlice.js 及其 fetchBookData 函数,但我无法弄清楚我错过了什么。我怎样才能克服这个问题?

这是完整的代码库:https://github.com/PhucDong/Redux-Bookstore

这是HomePage.js

中的代码
import { useState, useEffect } from "react";
import { ClipLoader } from "react-spinners";
import { useNavigate } from "react-router-dom";
import PaginationBar from "../components/PaginationBar";
import SearchForm from "../components/SearchForm";
import { FormProvider } from "../form";
import { useForm } from "react-hook-form";
import {
  Container,
  Alert,
  Box,
  Card,
  Stack,
  CardMedia,
  CardActionArea,
  Typography,
  CardContent,
} from "@mui/material";
import { BACKEND_API } from "../config";
import { useDispatch, useSelector } from "react-redux";
import {
  fetchBookData,
} from "../service/bookList/bookListSlice";

const HomePage = () => {
  const [pageNum, setPageNum] = useState(1);
  const totalPage = 10;
  const limit = 10;

  const [loading, setLoading] = useState(false);
  const [query, setQuery] = useState("");
  const [errorMessage, setErrorMessage] = useState("");

  const navigate = useNavigate();
  const handleClickBook = (bookId) => {
    navigate(`/books/${bookId}`);
  };

  const bookData = useSelector((state) => state.bookList.books);
  const dispatch = useDispatch();

  useEffect(() => {
    setLoading(true);
    let url = `/books?_page=${pageNum}&_limit=${limit}`;
    if (query) {
      url += `&q=${query}`;
    }
    dispatch(fetchBookData(url));

    setLoading(false);
  }, [dispatch, pageNum, query]);

  //------React hook form
  const defaultValues = {
    searchQuery: "",
  };
  const methods = useForm({
    defaultValues,
  });
  const { handleSubmit } = methods;
  const onSubmit = (data) => {
    setQuery(data.searchQuery);
  };
  //------

  return (
    <Container>
      <Stack sx={{ display: "flex", alignItems: "center", m: "2rem" }}>
        <Typography variant="h3" sx={{ textAlign: "center" }}>
          Book Store
        </Typography>

        {errorMessage && <Alert severity="danger">{errorMessage}</Alert>}

        <FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
          <Stack
            spacing={2}
            direction={{ xs: "column", sm: "row" }}
            alignItems={{ sm: "center" }}
            justifyContent="space-between"
            mb={2}
          >
            <SearchForm />
          </Stack>
        </FormProvider>

        <PaginationBar
          pageNum={pageNum}
          setPageNum={setPageNum}
          totalPageNum={totalPage}
        />
      </Stack>

      <div>
        {loading ? (
          <Box sx={{ textAlign: "center", color: "primary.main" }}>
            <ClipLoader color="inherit" size={150} loading={true} />
          </Box>
        ) : (
          <Stack
            direction="row"
            spacing={2}
            justifyContent="space-around"
            flexWrap="wrap"
          >
            {bookData.map((book) => (
              <Card
                key={book.id}
                onClick={() => handleClickBook(book.id)}
                sx={{
                  width: "12rem",
                  height: "27rem",
                  marginBottom: "2rem",
                }}
              >
                <CardActionArea>
                  <CardMedia
                    component="img"
                    image={`${BACKEND_API}/${book.imageLink}`}
                    alt={`${book.title}`}
                  />
                  <CardContent>
                    <Typography gutterBottom variant="h5" component="div">
                      {`${book.title}`}
                    </Typography>
                  </CardContent>
                </CardActionArea>
              </Card>
            ))}
          </Stack>
        )}
      </div>
    </Container>
  );
};

export default HomePage;

这里是bookListSlice.js

中的代码
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import apiService from "../../apiService";

const initialState = {
  books: [],
  error: "",
};

export const fetchBookData = createAsyncThunk(
  "books/fetchBooks",
  async (url) => {
    const response = await apiService.get(url);
    return response.data;
  }
);

export const bookListSlice = createSlice({
  name: "bookList",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchBookData.pending, (state, action) => {
        state.status = "loading";
      })
      .addCase(fetchBookData.fulfilled, (state, action) => {
        state.status = "succeeded";
        state.books = state.books.concat(action.payload);
      })
      .addCase(fetchBookData.rejected, (state, action) => {
        state.status = "failed";
        state.error = action.error.message;
      });
  },
});

export default bookListSlice.reducer;

redux react-redux redux-toolkit
1个回答
0
投票

我查过了。您在 store.js 中遇到的问题

你必须这样调用减速器。

import bookListSlice from "./bookList/bookListSlice";

因为你导入了这个

不是这个

这就是现在的样子。

所以请告诉我这是否是您所问的问题。

© www.soinside.com 2019 - 2024. All rights reserved.