You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React项目Invalid Hook Call错误排查求助

问题分析与修复方案

核心错误点

1. 无效钩子调用(Invalid Hook Call)

  • Movies组件中错误地直接调用<Navigate>组件,而非使用useNavigate钩子实现编程式导航。
  • 导航逻辑完全错误:点击单部电影的"SEE MORE"时,不应传递整个movies数组作为路由参数,而是传递当前电影的imdbID。

2. "map is undefined"错误

  • Moviecard组件中,通过i参数请求OMDB单部电影详情时,接口返回的是单个对象而非数组,你错误地赋值了data.Search(该字段仅在s搜索接口返回数组时存在),导致desc变为undefined,调用map时抛出错误。
  • Movies组件中,OMDB返回的电影唯一标识是imdbID而非id,使用movie.id作为key会导致警告,且可能引发渲染问题。

修复后的Movies组件代码

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

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

function Movies() {
  const [movies, setMovies] = useState([]);
  const { id: title } = useParams();
  const [loading, setLoading] = useState(true);
  const navigate = useNavigate(); // 使用useNavigate钩子实现跳转

  // 点击SEE MORE时跳转到对应电影详情页
  const handleSeeMore = (imdbID) => {
    navigate(`/moviecard/${imdbID}`);
  };

  async function fetchMovies(searchTitle) {
    try {
      const { data } = await axios.get(`${API_URL}&s=${searchTitle}`);
      // 处理接口无结果的情况,避免setMovies为undefined
      setMovies(data.Search || []);
      setLoading(false);
    } catch (err) {
      console.error("获取电影列表失败:", err);
      setMovies([]);
      setLoading(false);
    }
  }

  useEffect(() => {
    if (title) {
      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}> {/* 使用正确的imdbID作为key */}
                  <div className="movie__img">
                    <img src={movie.Poster} alt={movie.Title} />
                    <div className="movie__content">
                      <h1>{movie.Title}</h1>
                      <h1>{movie.Year}</h1>
                      {/* 传递当前电影的imdbID */}
                      <p onClick={() => handleSeeMore(movie.imdbID)}>SEE MORE</p>
                    </div>
                  </div>
                </div>
              ))}
        </div>
      </div>
    </>
  );
}

export default Movies;

修复后的Moviecard组件代码

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 { id: imdbID } = useParams();
  const [movie, setMovie] = useState(null); // 单部电影是对象,初始值设为null
  const [loading, setLoading] = useState(true);

  async function fetchDesc() {
    try {
      const { data } = await axios.get(`${API_URL}&i=${imdbID}`);
      // 直接赋值整个返回对象,而非data.Search
      setMovie(data);
      setLoading(false);
    } catch (err) {
      console.error("获取电影详情失败:", err);
      setMovie(null);
      setLoading(false);
    }
  }

  useEffect(() => {
    if (imdbID) {
      fetchDesc();
    }
  }, [imdbID]); // 添加imdbID作为依赖,参数变化时重新请求

  return (
    <>
      <Nav />
      {loading ? (
        // 展示合理的骨架屏,避免使用未定义的movie属性
        <div className="movie__img--wrapper">
          <div className="skeleton-title"></div>
          <div className="skeleton-img"></div>
        </div>
      ) : movie ? (
        // 直接渲染单个电影对象,无需map
        <div className="movie__info--wrapper" key={movie.imdbID}>
          <h1>{movie.Title}</h1>
          <img src={movie.Poster} alt={movie.Title} />
          <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>
      ) : (
        <p>电影详情未找到</p>
      )}
    </>
  );
}

export default Moviecard;

额外优化点

  • 添加了错误捕获逻辑,避免接口请求失败导致页面崩溃。
  • 处理了接口无结果的边界情况,防止movies或movie为undefined。
  • 修正了路由参数的解构写法,提高代码可读性。
  • 为图片添加了正确的alt属性,符合无障碍标准。

内容的提问来源于stack exchange,提问作者Cam Watkins

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 00:44:52