redux 组件未从使用React/Toolkit和createAsyncThunk的状态接收数据

rta7y2nd  于 2022-11-12  发布在  React
关注(0)|答案(1)|浏览(122)

我试图传递数据到组件,我从API接收。我正在使用'createAsyncThunk'保存它的状态,而不是当试图获得我的数据,得到错误“未定义”。我理解它的发生,因为它需要一些时间来从API获得数据,但我如何才能迫使组件“等待”?我的代码有什么问题?
下面是我的代码:
第一步:从API中获取数据,过滤后推送到状态中。

import { generateRandom } from "../helpers/randomInt";

const API_URL = "https://akabab.github.io/superhero-api/api/all.json";

export const fetchHeroes = createAsyncThunk(
  "data_slice/fetchHeroes",
  async function (_, { rejectWithValue }) {
    try {
      const res = await fetch(API_URL);
      if (!res.ok) {
        throw new Error("Could not fetch cart data!");
      }
      const data = await res.json();

      const marvel_heroes = data.filter(
        (item) => item.biography.publisher == "Marvel Comics"
      );
      const dark_horse_heroes = data.filter(
        (item) => item.biography.publisher == "Dark Horse Comics"
      );
      const dc_heroes = data.filter(
        (item) => item.biography.publisher == "DC Comics"
      );

      const filtered_data = [
        ...marvel_heroes,
        ...dark_horse_heroes,
        ...dc_heroes,
      ];

      const heroesData = [];

      for (let index = 0; index < 49; index++) {
        const item = filtered_data[generateRandom(0, 439)];
        heroesData.push(item);
      }

      const main_data = [filtered_data, heroesData];
      return main_data;
    } catch (error) {
      return rejectWithValue(error.message);
    }
  }
);

const heroesSlice = createSlice({
  name: "data_slice",
  initialState: { heroes_data: [], isLoading: null, error: null },

  extraReducers: {
    [fetchHeroes.pending]: (state) => {
      state.isLoading = true;
    },
    [fetchHeroes.fulfilled]: (state, action) => {
      state.heroes_data = action.payload;
      state.isLoading = false;
    },
    [fetchHeroes.rejected]: (state) => {
      state.isLoading = false;
      state.error = "Something go wrong!";
      alert("aaa");
    },
  },
});

export default heroesSlice;

第2步:在“App.js”中使用“UseEffect”触发(使用调度)获取函数“fetchHeroes”,以便在应用程序启动时获取数据

import { Fragment, useState, useEffect } from "react";

import { useSelector, useDispatch } from "react-redux";
import { fetchHeroes } from "./store/heroes-slice";

import { Routes, Route } from "react-router-dom";

import Main from "./pages/Main";
import Heroes from "./pages/Heroes";
import Hero_page from "./pages/Hero_page";

import LoginModal from "./components/LoginModal";
import RegisterModal from "./components/RegisterModal";

function App() {
  const [scrollY, setScrollY] = useState(0);

  const isLoginModal = useSelector((state) => state.modal.isLoginModal);
  const isRegisterModal = useSelector((state) => state.modal.isRegisterModal);

  const dispatch = useDispatch();

  function logit() {
    setScrollY(window.scrollY);
    console.log(new Date().getTime());
  }

  useEffect(() => {
    function watchScroll() {
      window.addEventListener("scroll", logit);
    }
    watchScroll();
    return () => {
      window.removeEventListener("scroll", logit);
    };
  });

  useEffect(() => {
    dispatch(fetchHeroes());
  }, [dispatch]);

  return (
    <Fragment>
      {isRegisterModal && <RegisterModal></RegisterModal>}
      {isLoginModal && <LoginModal></LoginModal>}
      <Routes>
        <Route path="/" element={<Main />} />
        <Route path="/heroes" exact element={<Heroes scroll={scrollY} />} />
        <Route path="/heroes/:heroId" element={<Hero_page />}></Route>
      </Routes>
    </Fragment>
  );
}

export default App;

第3步:我尝试使用“usSelect”从state(heros_fetched_data)接收数据,但在尝试通过“map”解析数据时,出现错误“undefined”

import classes from "./Heroes.module.css";
import Header from "../components/Header";
import Footer from "../components/Footer.js";
import Hero_card from "../components/Hero_card";
import { useSelector } from "react-redux";
import { Link } from "react-router-dom";

export default function Heroes(props) {
  const heroes_fetched_data = useSelector((state) => state.heroes.heroes_data);
  const loadingStatus = useSelector((state) => state.heroes.isLoading);

  console.log(heroes_fetched_data);

  const heroes_cards = heroes_fetched_data[1].map((item, i) => (
    <Link to={`/heroes/${item.id}`} key={item.id + Math.random()}>
      <Hero_card
        key={i}
        img={item.images.lg}
        name={item.name}
        publisher={item.biography.publisher}
      />
    </Link>
  ));

  return (
    <div className={classes.main}>
      <Header scroll={props.scroll} />
      {!loadingStatus && (
        <section className={classes.heroes}>
          <ul className={classes.ully} id="heroes">
            {heroes_cards}
          </ul>
        </section>
      )}

      {loadingStatus && <p>Loading...</p>}
      <Footer />
    </div>
  );
}
im9ewurl

im9ewurl1#

因为提取是异步的,所以不能假定Heroes组件中的heroes_fetched_data在组件第一次呈现时就有数据。在尝试使用之前,需要检查该数据是否存在。如果还没有,组件应该呈现一个备用的“正在加载”状态。当提取完成时,组件应该自动重新呈现,此时heroes_fetched_data将具有您需要的数据,您可以继续。
大致上,您需要类似于以下伪代码的代码:

export default function Heroes(props) {
  const heroes_fetched_data = useSelector((state) => state.heroes.heroes_data);
  const loadingStatus = useSelector((state) => state.heroes.isLoading);

  if (!heroes_fetched_data) {
    return <p>{loadingStatus}</p>;
  }

  const heroes_cards = heroes_fetched_data[1].map((item, i) => (
    // ...
  );

  // proceed as normal
}

相关问题