【问题标题】:React/Redux/Redux-saga rendering only the last API valueReact/Redux/Redux-saga 只渲染最后一个 API 值
【发布时间】:2021-09-13 12:35:38
【问题描述】:

我是对 redux 工具包和 redux-saga 做出反应的新手,遇到了一个错误,它只呈现来自 moviedb api 的最后一个 api 调用值。此外,当我从 useSelector 控制台记录状态时,它会呈现多个值。这是我的代码

App.js

import "./App.css";
import Row from "./components/Row";
import requests from "./requests";

function App() {
  return (
    <div className="App">
      <Row
        title="Netflix Originals"
        fetchUrl={requests.fetchNetflixOriginals}
      />
      <Row title="Trending Now" fetchUrl={requests.fetchTrending} />
      {/* <Row title="Top Rated" fetchUrl={requests.fetchTopRated} />
      <Row title="Action Movies" fetchUrl={requests.fetchActionMovies} />
      <Row title="Horror Movies" fetchUrl={requests.fetchHorrorMovies} /> */}
    </div>
  );
}

export default App;

Store.js

import { configureStore, combineReducers } from "@reduxjs/toolkit";
import createSagaMiddleware from "redux-saga";
import { watcherSaga } from "./sagas/rootSaga";
import movieReducer from "./ducks/movieSlice";

const sagaMiddleware = createSagaMiddleware();

const reducer = combineReducers({
  movie: movieReducer,
});

const store = configureStore({
  reducer,
  middleware: [sagaMiddleware],
});

sagaMiddleware.run(watcherSaga);

export default store;

movieSlice.js

import { createSlice } from "@reduxjs/toolkit";

const movieSlice = createSlice({
  name: "movie",
  initialState: [],
  reducers: {
    getMovie() {},
    setMovie(state, action) {
      const movieData = action.payload;
      return { ...state, ...movieData };
    },
  },
});

export const { getMovie, setMovie } = movieSlice.actions;

export default movieSlice.reducer;

rootSaga.js

import { takeEvery, takeLatest } from "redux-saga/effects";
import { getMovie } from "../ducks/movieSlice";
import { handleGetMovie } from "./handlers/movies";

export function* watcherSaga() {
  yield takeEvery(getMovie.type, handleGetMovie);
}

处理程序

电影.js

import { call, put } from "redux-saga/effects";
import { requestGetMovie } from "../requests/movies";
import { setMovie } from "../../ducks/movieSlice";

export function* handleGetMovie(action) {
  try {
    const response = yield call(requestGetMovie, action.payload);
    const { data } = response;
    yield put(setMovie(data));
  } catch (error) {
    console.log(error);
  }
}

请求

电影.js

import axios from "axios";

const baseURL = "https://api.themoviedb.org/3";

export function requestGetMovie(url) {
  const URL = baseURL + url.fetchLink;
  return axios.request({
    method: "get",
    url: URL,
  });
}

requests.js

const APIKEY = "9cf4e09bc69e9849477a8ac79d29a205";

const requests = {
  fetchTrending: `/trending/all/week?api_key=${APIKEY}&language=en=us`,
  fetchNetflixOriginals: `/discover/tv?api_key=${APIKEY}&with_networks=213`,
  fetchTopRated: `/movie/top_rated?api_key=${APIKEY}&language=en=us`,
  fetchActionMovies: `/discover/movie?api_key=${APIKEY}&with_generes=28`,
  fetchHorrorMovies: `/discover/movie?api_key=${APIKEY}&with_genres=27
    `,
};

export default requests;

Row.js

import React, { useState, useEffect } from "react";
import styled from "styled-components";
import { useDispatch, useSelector } from "react-redux";
import { getMovie } from "../redux/ducks/movieSlice";

function Row({ title, fetchUrl }) {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(
      getMovie({
        fetchLink: fetchUrl,
      })
    );
  }, [dispatch, fetchUrl]);
  const movie = useSelector((state) => {
    return state.movie.results;
  });
  console.log(movie);

  return (
    <RowContainer>
      {title}
      <CardsContainer>{movie && movie[0].name}</CardsContainer>
    </RowContainer>
  );
}

export default Row;

const RowContainer = styled.div`
  color: white;
`;

const CardsContainer = styled.div`
  color: white;
`;

Netflix 原件应该显示 Lucifer,同时它从最新状态值渲染 Money Heist,并且如果我 console.log 电影值,即使我在 app.js 上只有两行组件,也会重复多个值。如果我在 app.js 上有 5 次 Row 组件,它会在控制台上显示该值 25 次。

image

image2

【问题讨论】:

    标签: javascript reactjs redux redux-saga redux-toolkit


    【解决方案1】:

    您的问题在于文件movieSlice.js,正是这里:

    setMovie(state, action) {
     ​const movieData = action.payload;
     ​return { ...state, ...movieData };
    }
    

    每次调用setMovie 操作时,您都会覆盖电影对象。

    您应该做的是为不同的电影类型设置单独的操作,如下所示:

    const movieSlice = createSlice({
      name: "movie",
      initialState: {
        trendingMovies: [],
        actionMovies: [],
      },
      reducers: {
        setTrendingMovies(state, action) {
          state.trendingMovies = action.payload;
        },
        setActionMovies(state, action) {
          state.actionMovies = action.payload;
        }
      },
    });
    
    

    【讨论】:

      猜你喜欢
      • 2019-02-21
      • 1970-01-01
      • 2019-02-20
      • 1970-01-01
      • 1970-01-01
      • 2016-02-22
      • 1970-01-01
      • 1970-01-01
      • 2018-03-16
      相关资源
      最近更新 更多