javascriptreactjsaxiosruntime-errorreact-router-dom

I keep receiving an error for an invalid hook call not sure what to do


I am working on an API project using React-Router-DOM for navigation and when the initial search results are called I have an array of 8 movies that are shown based on a keyword from the user's search query. Once the user has chosen the specific movie they are looking for by clicking the "SEE MORE" button attached to the movie card it is supposed to redirect to another page that shows specific details about the selected movie, but instead I keep getting uncaught runtime errors that is saying I have an invalid hook call but I'm not sure where I went wrong. moviecard displaying that "map" is undefined Below is the code that is first used after the original search query :

import axios from "axios";
import React, { useEffect, useState } from "react";
import Nav from "../ui/Nav";
import { Navigate, useParams } from "react-router-dom";

const API_URL = "http://www.omdbapi.com/?apikey=cca6a59";

function Movies() {
  const [movies, setMovies] = useState([]);
  const params = useParams();
  const title = params.id;
  const [loading, setLoading] = useState(true);

  async function onSearch() {
    await fetchMovies();

    Navigate(`/moviecard/${movies}`);

    fetchMovies(movies)
  }

  async function fetchMovies(title) {
    const { data } = await axios.get(`${API_URL}&s=${title}`);
    setMovies(data.Search);
    setLoading(false);
  }

  useEffect(() => {
    fetchMovies(title);
  }, [title]);

  return (
    <>
      <Nav />
      <div className="movie__row">
        <div className="movie__wrapper">
          {loading
            ? new Array(8).fill(0).map((_, index) => (
                <div className="movie" key={index}>
                  <div className="movie__img--skeleton">
                    <div className="movie__title--skeleton">
                      <div className="movie__year--skeleton"></div>
                    </div>
                  </div>
                </div>
              ))
            : movies.map((movie) => (
                <div className="movie" key={movie.id}>
                  <div className="movie__img">
                    <img src={`${movie.Poster}`} alt="poster" />
                    <div className="movie__content">
                      <h1>{movie.Title}</h1>
                      <h1>{movie.Year}</h1>
                      <p onClick={() => onSearch()}>SEE MORE</p>
                    </div>
                  </div>
                </div>
              ))}
        </div>
      </div>
    </>
  );
}

export default Movies;

This is the code after the user selects "SEE MORE" after selecting the specific movie:

import { useParams } from "react-router-dom";
import Nav from "../ui/Nav";
import { useEffect, useState } from "react";
import axios from "axios";

const API_URL = "http://www.omdbapi.com/?apikey=cca6a59";

function Moviecard() {
  const params = useParams();
  const imdbID = params.id;
  const [desc, setDesc] = useState([]);
  const [loading, setLoading] = useState(true);

  async function fecthDesc() {
    const { data } = await axios.get(`${API_URL}&i=${imdbID}`);
    setDesc(data.Search);
    setLoading(false);
  }

  useEffect(() => {
    fecthDesc();
  }, []);

  return (
    <>
      <Nav />

      {loading
        ? new Array(1).fill(0).map((_, movie) => (
            <div className="movie__img--wrapper">
              <h1>${movie.Title}</h1>
              <img src={`${movie.Poster}`} alt="" />
            </div>
          ))
        : desc.map((movie) => (
            <div className="movie__info--wrapper" key={imdbID}>
              <h3>
                <span className="red">Released: </span>${movie.Released}
              </h3>
              <h3>
                <span className="red">Actors: </span>${movie.Actors}
              </h3>
              <h3>
                <span className="red">Genre: </span>${movie.Genre}
              </h3>
              <h3>
                <span className="red">Director: </span>${movie.Director}
              </h3>
              <h3>
                <span className="red">Writer: </span>${movie.Writer}
              </h3>
              <h3>
                <span className="red">Language: </span>${movie.Language}
              </h3>
              <h3>
                <span className="red">Plot: </span>${movie.Plot}
              </h3>
            </div>
          ))}
    </>
  );
}

export default Moviecard;

I'm sure it is something small that I'm just forgetting but I don't know how to attack this problem.


Solution

  • The code is directly calling, e.g invoking, the Navigate component instead of passing it as JSX to be rendered by React. This isn't what you want to do here though.

    Example:

    import { useNavigate, useParams } from "react-router-dom";
    
    function Movies() {
      const navigate = useNavigate();
      const { id: title } = useParams();
    
      const [movies, setMovies] = useState([]);
      const [loading, setLoading] = useState(true);
    
      function onSearch(movieId) {
        navigate(`/moviecard/${movieId}`);
      }
    
      useEffect(() => {
        async function fetchMovies(title) {
          try {
            const { data } = await axios.get(`${API_URL}&s=${title}`);
            setMovies(data.Search);
          } catch(error) {
            // catch and handle/ignore
          } finally {
            setLoading(false);
          }
        }
    
        fetchMovies(title);
      }, [title]);
    
      return (
        <>
          <Nav />
          <div className="movie__row">
            <div className="movie__wrapper">
              {loading
                ? new Array(8).fill(0).map((_, index) => (
                    <div className="movie" key={index}>
                      <div className="movie__img--skeleton">
                        <div className="movie__title--skeleton">
                          <div className="movie__year--skeleton"></div>
                        </div>
                      </div>
                    </div>
                  ))
                : movies.map((movie) => (
                    <div className="movie" key={movie.imdbID}>
                      <div className="movie__img">
                        <img src={`${movie.Poster}`} alt="poster" />
                        <div className="movie__content">
                          <h1>{movie.Title}</h1>
                          <h1>{movie.Year}</h1>
                          <p onClick={() => onSearch(movie.imdbID)}>SEE MORE</p>
                        </div>
                      </div>
                    </div>
                  ))}
            </div>
          </div>
        </>
      );
    }