React.js URL ID Changes but not showing the component

Viewed 174

I'm building an movie app in react using router v6. Here there are several pages. From the home screen when I click on a move poster it takes me to the move details page(/movie-detail/242) and it works fine. Inside the movie details page I have used the same poster component like in the home page to show similar movies like the current move. But here when I click on a movie poster the URL ID changes (/movie-detail/1045), but the new move detailenter code here is not loaded. In short I'm trying to access a moveDetail Page with in a moveDetail page. Please Help Me.. Thank you

App.js File

import React, { useEffect } from "react";
import "./App.css";
import HomeScreen from "./screens/HomeScreen";
import { BrowserRouter, Routes, Route, Link, Outlet } from "react-router-dom";
import LoginScreen from "./screens/LoginScreen";
import { auth } from "./firebase";
import { useDispatch, useSelector } from "react-redux";
import { login, logout, selectUser } from "./features/userSlice";
import ProfileScreen from "./screens/ProfileScreen";
import MovieDetail from "./movieDetail/MovieDetail";
import LoadingSpinner from "./LoadingSpinner";
import AppError from "./UI/AppError";
import SearchHome from "./search/SearchHome";

function App() {
  const user = useSelector(selectUser);
  const dispatch = useDispatch();

  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((userAuth) => {
      if (userAuth) {
        //Logged in
        dispatch(
          login({
            uid: userAuth.uid,
            email: userAuth.email,
          })
        );
      } else {
        //Logged out
        dispatch(logout());
      }
    });
    return unsubscribe;
  }, [dispatch]);

  return (
    <div className="app">
      {!user ? (
        <LoginScreen />
      ) : (
        <Routes>
          <Route path="/profile" element={<ProfileScreen />} />
          <Route path="/" element={<HomeScreen />} />
          <Route path="/search" element={<SearchHome />} />
          <Route path="/movie-detail/:movieId" element={<MovieDetail />} />
          <Route path="*" element={<AppError />} />
        </Routes>
      )}
    </div>
  );
}

export default App;

Index.js File

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import store from "./app/store";
import { Provider } from "react-redux";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter } from "react-router-dom";

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </Provider>
  </React.StrictMode>,
  document.getElementById("root")
);

serviceWorker.unregister();

//HomeScreen

import React, { useEffect } from "react";
import Banner from "../Banner";
import "./HomeScreen.css";
import Nav from "../Nav";
import Row from "../Row";
import requests from "../Requests";
import Footer from "../Footer";
import RowLarge from "../RowLarge";

function HomeScreen(props) {
  useEffect(() => {
    window.scrollTo(0, 0);
  }, []);

  return (
    <div className="homeScreen">
      <Nav />
      <Banner />
      <RowLarge
        title="NETFLIX ORIGINALS"
        fetchUrl={requests.fetchUpcoming2}
        isLargeRow
      />
      <Row title="Trending Now" fetchUrl={requests.fetchTrending} />
      <Row title="Top Rated" fetchUrl={requests.fetchTopRated} />
      <Row title="Upcoming" fetchUrl={requests.fetchUpcoming3} />
      <Row title="Action Movies" fetchUrl={requests.fetchActionMovies} />
      <Row title="Comedy Movies" fetchUrl={requests.fetchComedyMovies} />
      <Row title="Horror Movies" fetchUrl={requests.fetchHorrorMovies} />
      <Row title="Romance Movies" fetchUrl={requests.fetchRomanceMovies} />
      <Row title="Documentaries" fetchUrl={requests.fetchDocumentaries} />
      <Footer />
    </div>
  );
}

export default HomeScreen;

Movie Details Page

import axios from "axios";
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Footer from "../Footer";
import Nav from "../Nav";
import Blocker from "../UI/Blocker";
import MovieBanner from "./MovieBanner";
import "./MovieDetail.css";
import MoviePoster from "./MoviePoster";
import MovieTag from "./MovieTag";
import Row from "../Row";
import requests from "../Requests";
import MovieAbout from "./MovieAbout";
import MovieComingSoon from "./MovieComingSoon";
import MovieVideo from "./MovieVideo";
import MovieSimilar from "./MovieSimilar";
import MovieCast from "./MovieCast";
import MovieReview from "./MovieReview";
import LoadingSpinner from "../LoadingSpinner";

function MovieDetail() {
  const { movieId } = useParams();
  const [movie, setMovie] = useState(null);
  const API_KEY = "################################";


  useEffect(() => {
    axios
      .get(
        `https://api.themoviedb.org/3/movie/${movieId}?api_key=${API_KEY}&language=en-US`
      )
      .then((res) => {
        setMovie(res.data);
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);

  //scroll to top each time this component is mounted
  useEffect(() => {
    window.scrollTo(0, 0);
  }, []);

  return (
    <>
      {movie ? (
        <div>
          <Nav />
          <MovieBanner movie={movie} />
          <MovieTag />
          <MovieCast movieId={movieId} apiKey={API_KEY} />
          <MoviePoster movie={movie} />
          <MovieAbout movie={movie} />
          <MovieVideo movie={movie} movieId={movieId} apiKey={API_KEY} />
          <MovieReview movieId={movieId} apiKey={API_KEY} />
          <MovieSimilar movieId={movieId} apiKey={API_KEY} />
          <MovieComingSoon apiKey={API_KEY} />
          <Footer />
        </div>
      ) : (
        <LoadingSpinner />
      )}
    </>
  );
}

export default MovieDetail;

//Reused Poster Component

import { render } from "@testing-library/react";
import React, { useEffect, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "./axios";
import "./Row.css";

function Row({ title, fetchUrl, isLargeRow = false }) {
  const [movies, setMovies] = useState([]);
  const postersRef = useRef(0);
  const [scrollPossition, setScrollPossition] = useState(0);
  const navigate = useNavigate();

  //left right horizontal scroll
  const scroll = (scrollOffset) => {
    postersRef.current.scrollLeft += scrollOffset;
  };

  const setLeftArrowVisibility = () => {
    let scrollPossitionValue = postersRef.current.scrollLeft;
    setScrollPossition(scrollPossitionValue + 600);
  };

  const setRightArrowVisibility = () => {
    let scrollPossitionValue = postersRef.current.scrollLeft;
    setScrollPossition(scrollPossitionValue - 600);
  };

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

  useEffect(() => {
    async function fetchData() {
      const request = await axios.get(fetchUrl);
      setMovies(request.data.results);
      return request;
    }

    fetchData();
  }, [fetchUrl]);

  const renderLeftArrow = () => {
    if (scrollPossition > 0) {
      return (
        <svg
          onClick={() => {
            scroll(-600);
            setRightArrowVisibility();
          }}
          viewBox="0 0 18 18"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path
            fill="currentColor"
            d="M11.56 5.56L10.5 4.5 6 9l4.5 4.5 1.06-1.06L8.12 9z"
          ></path>
        </svg>
      );
    }
  };
  const renderRightArrow = () => {
    if (scrollPossition <= 3000) {
      return (
        <svg
          onClick={() => {
            scroll(600);
            setLeftArrowVisibility();
          }}
          viewBox="0 0 18 18"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path
            fill="currentColor"
            d="M11.56 5.56L10.5 4.5 6 9l4.5 4.5 1.06-1.06L8.12 9z"
          ></path>
        </svg>
      );
    }
  };

  return (
    <div className="row">
      <h2>{title}</h2>
      <div ref={postersRef} className="row__posters">
        <div className="row__arrow-left">{renderLeftArrow()}</div>
        {movies.map(
          (movie) =>
            ((isLargeRow && movie.poster_path) ||
              (!isLargeRow && movie.backdrop_path)) && (
              <div
                key={movie.id + Math.random() - Math.random()}
                className="row__imageContainer"
              >
                <img
                  className={`row__poster`}
                  src={`${base_url}${
                    isLargeRow ? movie.poster_path : movie.backdrop_path
                  }`}
                  alt={movie.name}
                />
                <div
                  className="row__imageOverlay"
                  onClick={() => {
                    navigate(`/movie-detail/${movie.id}`);
                  }}
                >
                  <div className="row__overlayText">
                    <p> {movie?.vote_average}</p>
                    <p>IMDB Rating</p>
                  </div>
                </div>
                <div className="row__movieName">
                  {" "}
                  {movie?.title || movie?.name || movie?.original_name}
                </div>
              </div>
            )
        )}
        <div className="row__arrow-right">{renderRightArrow()}</div>
      </div>
    </div>
  );
}

export default Row;
1 Answers

If I'm understanding the issue correctly you are on a specific movie detail page, and click a link to view a different specific movie's details and the MovieDetail doesn't respond to the new movie id.

Use the movieId route param in the useEffect hook's dependency array so new movie details are fetched when the movieId changes.

Example:

const { movieId } = useParams();
const [movie, setMovie] = useState(null);

useEffect(() => {
  axios
    .get(
      `https://api.themoviedb.org/3/movie/${movieId}?api_key=${API_KEY}&language=en-US`
    )
    .then((res) => {
      setMovie(res.data);
    })
    .catch((err) => {
      console.log(err);
    });
}, [movieId]);
Related