使用Axios与TheMovieDB API实现电影详情页的路由传参问题
解决电影详情页movieId传递失败导致的404问题
问题根源
- 后端Express接口未定义路由参数,无法接收前端传来的movieId
- 前端请求后端时,没有传递实际的movieId,而是用了
:movieId占位符 - 后端请求TMDB API时,同样用了占位符而非实际参数值
第一步:修正后端server.js
修改接口路由,让它能捕获movieId参数,并正确传递给TMDB API:
const express = require('express'); const axios = require('axios'); const app = express(); const port = 5000; const cors = require('cors'); app.use(cors({ origin: 'http://localhost:3000' })); const API_KEY = '......'; // 电影列表接口保持不变 app.get('/api/movies', async (req, res) => { try { const response = await axios.get( `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}` ); res.json(response.data.results); } catch (error) { res.status(500).send('Error fetching data from API'); } }); // 修正电影详情接口:添加路由参数:movieId app.get('/api/movieDetails/:movieId', async (req, res) => { try { // 从路由参数中获取movieId const { movieId } = req.params; const detailResponse = await axios.get( `https://api.themoviedb.org/3/movie/${movieId}?api_key=${API_KEY}` ); res.status(200).json(detailResponse.data); } catch (error) { // 区分TMDB请求失败或其他错误 res.status(error.response?.status || 500).send('Error fetching movie details'); } }); app.listen(port, () => { console.log(`Backend is running on http://localhost:${port}`); });
第二步:修正前端MovieDetailComponent.js
用React Router的useParams获取路由参数,正确请求后端接口,并优化状态处理:
import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { useParams } from 'react-router-dom'; // 引入useParams const posterUrl = 'https://media.themoviedb.org/t/p/w220_and_h330_face'; const posterDetailUrl = 'https://media.themoviedb.org/t/p/w300_and_h450_bestv2'; const backdropBaseUrl = 'https://media.themoviedb.org/t/p/w1920_and_h800_multi_faces'; // 只存基础路径,后续拼接图片地址 const MovieDetail = () => { const { movieId } = useParams(); // 从路由获取movieId const [movie, setMovie] = useState(null); // 直接存储电影对象,无需转数组 const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const fetchData = async () => { setIsLoading(true); try { // 请求后端接口,传递实际的movieId const response = await axios.get(`http://localhost:5000/api/movieDetails/${movieId}`); setMovie(response.data); setError(null); } catch (err) { setError(err.message); setMovie(null); } finally { setIsLoading(false); } }; useEffect(() => { if (movieId) { // 确保movieId存在再发起请求 fetchData(); } }, [movieId]); // movieId变化时重新请求数据 if (isLoading) return <div>加载中...</div>; if (error) return <div>错误:{error}</div>; if (!movie) return <div>未找到电影数据</div>; return ( <div className="App" style={{ backgroundImage: `url(${backdropBaseUrl + movie.backdrop_path})`, backgroundSize: 'cover', padding: '15px' }}> <div style={{ margin: '15px', padding: '15px', backgroundColor: 'rgba(255,255,255,0.7)' }}> <h1>Watch This</h1> <h2>{movie.title || movie.original_title}</h2> <div> <img src={`${posterUrl + movie.poster_path}`} alt={movie.title} style={{ maxWidth: '220px' }} /> <p> <strong>★ {movie.vote_average.toFixed(1)}</strong> ({movie.vote_count}) | {movie.runtime} minutes </p> </div> <div> <h4>Overview</h4> <p>{movie.overview}</p> <h4>Genres</h4> <p>{movie.genres.map(g => g.name).join(', ')}</p> </div> </div> </div> ); }; export default MovieDetail;
关键优化点说明
- 后端路由参数:通过
:movieId定义路由参数,Express自动将URL对应值存入req.params.movieId - 前端路由参数:用
useParams替代手动切割路径,更可靠且符合React Router最佳实践 - 状态处理:直接存储电影对象而非数组,取值更直观(如
movie.title比data[10]可读性更高) - 用户体验:添加加载、错误、空数据的UI反馈,避免页面空白或混乱
内容的提问来源于stack exchange,提问作者Wes Hightower
相关产品推荐
相关产品推荐

