使用 redux 调用的 API 被延迟

Posted

技术标签:

【中文标题】使用 redux 调用的 API 被延迟【英文标题】:Api calling with redux is getting delayed 【发布时间】:2021-10-01 00:58:09 【问题描述】:

**在 useEffect 钩子中,我试图对大约 120 个单词的电影进行小描述。 useEffect 中的任务就是这样的**

    通过redux调用api 检查是否有电影和movie.overview 然后从 api 获得的概述中进行小描述

但是 useState 视图没有及时反映,就好像我选择电影黑寡妇一样,它会显示默认视图 ie('lorem .....'),然后如果我从模板中选择另一部电影,它会显示给我上一部电影黑寡妇的描述

import React,  useEffect, useState  from "react";
import "./MovieTemplate.css";
import Play from "@material-ui/icons/PlayArrow";
import Add from "@material-ui/icons/Add";
import Share from "@material-ui/icons/Share";
import  useParams  from "react-router-dom";
import  connect  from "react-redux";
import  fetchMovie  from "../../redux/actions/postActions";

const IMG_URL = "https://image.tmdb.org/t/p/original/";

function MovieTemplate( fetchMovie, movie ) 
  const  id  = useParams();

  const desc = [];

  const [view, setView] = useState(
    "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem 
        Ipsum has been the industry standard dummy"
  );

  useEffect(() => 
    const load = async () => 
      await fetchMovie(id);
    ;
    load();
    console.log("id ", id);
    console.log("img ", `$IMG_URL$movie.backdrop_path`);
    if (movie && movie.overview) 
      for (let i = 0; i < 124; i++) 
        desc.push(movie.overview[i]);
      
      const a = desc.join("");
      setView(a);
      console.log("desc ", desc.join(""));
    
  , []);

  return (
    <div className="movieTemplate">
      <div className="movieTemplate-main">
        <div className="movieTemplate-body">
          <div className="movieTemplate-content">
            <div className="movieTemplate-content-inside">
              <p className="movieTemplate-content-badge">VIP</p>
              <p className="movieTemplate-content-title">
                movie.title ? movie.title : "Black Panther"
              </p>
              <p className="movieTemplate-content-time">
                1 hr 33 min . 2021 . Musical . 15+ . Hindi
              </p>
              <p className="movieTemplate-content-description">
                movie.overview
                  ? `$view...`
                  : "Lorem Ipsum is simply dummy text of the printing and typesetting 
                industry. Lorem Ipsum has been the industry standard dummy"
              </p>
              <div className="movieTemplate-content-player">
                <span className="movieTemplate-watch">
                  <Play
                    style= fontSize: 30, color: "#fff" 
                    className="movieTemplate-play-icon"
                  />
                  <p className="movieTemplate-watch-movie">Watch Movie</p>
                </span>
                <div className="movieTemplate-share-watch">
                  <span className="movieTemplate-watch-list">
                    <Add
                      style= fontSize: 30, color: "#fff" 
                      className="movieTemplate-add-icon"
                    />
                    <p className="movieTemplate-add-movie">WATCHLIST</p>
                  </span>
                  <span className="movieTemplate-share">
                    <Share
                      style= fontSize: 30, color: "#fff" 
                      className="movieTemplate-share-icon"
                    />
                    <p className="movieTemplate-share-movie">SHARE</p>
                  </span>
                </div>
              </div>
            </div>
          </div>
          <img
            src=
              movie.backdrop_path
                ? `$IMG_URL$movie.backdrop_path`
                : "https://cdn.guidingtech.com/media/assets/_1200x630_crop_center- 
                   center_82_none/Black-Panther-Movie-Wallpapers.jpg?mtime=1516263479"
            
            
            className="movieTemplate-img"
          />
        </div>
      </div>
      <span className="movieTemplate-tablet-watch">
        <Play
          style= fontSize: 30, color: "#fff" 
          className="movieTemplate-tablet-play-icon"
        />
        <p className="movieTemplate-tablet-watch-movie">Watch Movie</p>
      </span>
    </div>
  );


const mapStateTOProps = (state) => (
  movie: state.posts.movie,
);

export default connect(mapStateTOProps,  fetchMovie )(MovieTemplate);

redux

import  FETCH_TREND_MOVIE, FETCH_TREND_SERIES, FETCH_MOVIE, GET_MOVIE_ID  from "./types";
import api from "../Api"; 
import  fetch_movie, fetch_trend_movie, fetch_trend_series  from '../../services/URL';

export const fetchTrendMovie = () => async (dispatch) => 
  const response = await api("GET", fetch_trend_movie, api_key:"09a103acc6695c0ecde189600656e038", language: "en-US")
  response.data.results.length = 20
  console.log("response 1", response.data.results)
  return dispatch( type:FETCH_TREND_MOVIE, payload:response.data.results )



export const fetchTrendSeries = () => async (dispatch) => 
  const response = await api("GET", fetch_trend_series, api_key:"09a103acc6695c0ecde189600656e038", language: "en-US")
  response.data.results.length = 20
  console.log("response 2", response.data.results)
  return dispatch( type:FETCH_TREND_SERIES, payload:response.data.results )



export const fetchMovie = (id) => async (dispatch) => 
  const response = await api("GET", `$fetch_movie$id`, api_key:"09a103acc6695c0ecde189600656e038", language: "en-US")
  console.log("response 3", response)
  return dispatch( type:FETCH_MOVIE, payload:response.data )

通过 axios 的 api

import axios from 'axios';
import  BASE_URL  from '../services/URL';

export const api = async (method, apiUrl, parameter) => 
    var options = 
        method: method,
        url: BASE_URL+apiUrl,
        params: parameter,
      ;

      const response = await axios.request(options)
      return response;

【问题讨论】:

【参考方案1】:

您应该将 id 作为第二个参数传递给 useEffect,这样只要它发生变化,就会调用 effect。

useEffect(() => 
    const load = async () => 
      await fetchMovie(id);
    ;
    load();
    console.log("id ", id);
    console.log("img ", `$IMG_URL$movie.backdrop_path`);
    if (movie && movie.overview) 
      for (let i = 0; i < 124; i++) 
        desc.push(movie.overview[i]);
      
      const a = desc.join("");
      setView(a);
      console.log("desc ", desc.join(""));
    
  , [id]);

【讨论】:

以上是关于使用 redux 调用的 API 被延迟的主要内容,如果未能解决你的问题,请参考以下文章

使用redux时,React主要组件被调用两次

使用 Redux 的 useEffect 竞争条件

模拟 API 调用时未填充 Redux 存储

redux-saga 与 redux 一起使用会导致 render() 被调用两次

react redux 同步调用

使用 redux 响应原生 axios api 调用