как предотвратить многократную повторную визуализацию в react

#reactjs #redux #redux-toolkit

Вопрос:

 import { useSelector, useDispatch } from "react-redux";
import { useEffect, useState } from "react";
import { useHistory } from "react-router-dom";
import { IoMdArrowRoundBack } from "react-icons/io";
import axios from "axios";

import { fetchMovies } from "../../feautures/movies/moviesSlice";
import Rating from "../../components/UI/Rating/Rating";
import request from "../../requests";

import "./SingleMoviePage.scss";
import SimilarMovies from "../../components/SimilarMovies/SimilarMovies";


const SingleMoviePage = ({ match }) => {
  const dispatch = useDispatch();
  const [movieDetails, setMovieDetails] = useState({});
  const [movieCredits, setMovieCredits] = useState({});

  const history = useHistory();

  console.log("single rendered")

  // number month to string
  const date = new Date(movieDetails.release_date);
  const dateWithMonthName =
    date.getFullYear()  
    "-"  
    date.toLocaleString("en-EN", { month: "long" })  
    "-"  
    date.getDay();

  /*  params */
  const movieId = match.params.id;
  const page = match.params.page;
  const genre = match.params.genre;

  /* movies reducer handle */
  const moviesStatus = useSelector((state) => state.movies.status);


  /* base urls */
  const baseImgUrl = "https://image.tmdb.org/t/p/original";
  const movieDetailUrl = `https://api.themoviedb.org/3/movie/${movieId}?api_key=c057c067b76238e7a64d3ba8de37076eamp;language=en-US`;
  const movieCastUrl = `https://api.themoviedb.org/3/movie/${movieId}/credits?api_key=c057c067b76238e7a64d3ba8de37076eamp;language=en-US`;

  // go home page
  const goHOme = () => {

    history.goBack()
  };

  // fetch movie cast
  useEffect(() => {
    const fetchMovieCast = async () => {
      let response = await axios.get(movieCastUrl);
      response = response.data;
      setMovieCredits(response);
    };
    fetchMovieCast();


  }, [movieCastUrl]);

  // fetch movie details
  useEffect(() => {
    const fetchMovieDetails = async () => {
      let response = await axios.get(movieDetailUrl);
      response = response.data;
      setMovieDetails(response);
    };

    fetchMovieDetails();
  }, [movieDetailUrl]);

  let content;
  if (moviesStatus === "loading") {
  } else if (moviesStatus === "succeeded") {
    content = (
      <div
        className="single-movie__container"
        style={{
          backgroundImage: `url(${
            movieDetails.backdrop_path
              ? baseImgUrl   movieDetails.backdrop_path
              : baseImgUrl   movieDetails.poster_path
          })`,
        }}
      >
        <div className="single-movie__details">
          <IoMdArrowRoundBack
            className="single-movie__back"
            onClick={goHOme}
            size={65}
            color={"#e50914"}
          />
          <h1 className="single-movie__title">{movieDetails.title}</h1>
          <div className="single-movie__rate">
            <Rating
              rating={movieDetails.vote_average}
              className="single-movie__stars"
            />
          </div>
          <p className="single-movie__overview">{movieDetails.overview}</p>

          <div className="single-movie__informations single-movie__informations--genres">
            <label className="single-movie__informations-heading">Genres</label>
            <div className="single-movie__informations-container">
              {movieDetails.genres?.map((genre) => {
                return <div className="single-movie__info">{genre.name}</div>;
              })}
            </div>
          </div>

          <div className="single-movie__informations single-movie__informations--stars">
            <label className="single-movie__informations-heading">
              Starring
            </label>
            <div className="single-movie__informations-container">
              {movieCredits.cast?.slice(0, 4).map((star) => {
                return <div className="single-movie__info">{star.name}</div>;
              })}
            </div>
          </div>

          <div className="single-movie__informations single-movie__informations--released">
            <label className="single-movie__informations-heading">
              Release Date
            </label>
            <div className="single-movie__informations-container">
              <div className="single-movie__info">{dateWithMonthName}</div>
            </div>
          </div>

          <div className="single-movie__informations single-movie__informations--production">
            <label className="single-movie__informations-heading">
              Production
            </label>
            <div className="single-movie__informations-container">
              {movieDetails.production_countries?.slice(0, 2).map((country) => {
                return <div className="single-movie__info">{country.name}</div>;
              })}
            </div>
          </div>
        </div>
        <SimilarMovies movieId={movieId} />
      </div>
    );
  }

  useEffect(() => {
    if (genre === "POPULAR") {
      dispatch(fetchMovies(request.fetchPopular(page)));
    } else if (genre === "NOW PLAYING") {
      dispatch(fetchMovies(request.fetchNowPlaying(page)));
    } else if (genre === "UP COMING") {
      dispatch(fetchMovies(request.fetchUpComing(page)));
    }
  }, [dispatch, genre, page]);


  return <div className="single-movie">{content}</div>;
};

export default SingleMoviePage;
 

Привет всем.Когда я нажал на карточку compenent, она привела меня к компоненту SingleMoviePage.Но компонент SingleMoviePage перерисовывается пять раз.Как я могу найти источник этой проблемы ? И как я могу это предотвратить ? Наконец, есть ли какие-либо проблемы с получением MovieCast и MovieDetails в одном и том же крючке useffect ?

репо на github : https://github.com/UmutPalabiyik/hope-movie-app ДЕМОНСТРАЦИЯ : https://hope-movie.web.app/page/1

Комментарии:

1. Я также столкнулся с той же проблемой из-за зависимостей в useEffect.

Ответ №1:

Первые 2 крючка useEffect извлекают данные отдельно, которые затем обновляют ваши локальные состояния, что затем запускает повторную визуализацию.

Если вы не хотите повторно визуализировать после каждой выборки данных (обновления состояния), я бы предложил добавить loading состояние. Сначала установите значение true и верните значок загрузки в качестве содержимого. Затем, после того как оба movieDetails и movieCredits были заполнены, установите значение false и верните фактическое содержимое. Это должно отображаться в общей сложности дважды.

Вы рассматривали graphql? GraphQL может объединить ваши вызовы api в один, а также обрабатывать состояние загрузки и состояние ошибки.

Какое бы решение у вас ни было, повторный рендеринг произойдет, когда вы будете получать данные. Начальный рендеринг не будет содержать никаких данных, и после извлечения данных он должен быть повторно отрисован.

Комментарии:

1. Tnx так много. И можете ли вы проверить мой запрос, который гласит: «css-анимация не работает должным образом после загрузки reactjs» в моем профиле. Все равно я не мог исправить 🙂

Ответ №2:

Вы должны использовать только один хук useEffect, ваш код выполняется для всех трех. С остальным React справится сам.