
在 react 18 + react router v6 应用中,可通过路由配置传递 props(如 `listmovies`)并结合 `uselocation` 监听路由变化,实现组件逻辑的动态化与复用,避免硬编码和重复渲染问题。
要在 React 18 中让 Movielist 组件根据当前路由动态获取不同电影列表(如 / 对应 now_playing,/top-rated 对应 top_rated),核心在于将路由意图显式地作为 prop 传入组件,并在组件内部响应式使用该值——而非依赖 URL 解析或状态推断。
首先,确保已在 Movielist.jsx 中正确接收并使用 listMovies prop:
import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom'; // ✅ 必须引入
import axios from 'axios';
import './Movielist.css';
import Moviecard from '../Moviecard/Moviecard';
function Movielist({ listMovies }) { // ✅ 解构接收路由传入的 prop
const API_URL = 'https://api.themoviedb.org/3';
const [movies, setMovies] = useState([]);
const location = useLocation(); // ✅ 用于监听路由变更
const getMovies = async () => {
try {
const response = await axios.get(`${API_URL}/movie/${listMovies}`, {
params: {
api_key: process.env.REACT_APP_API_KEY,
},
});
setMovies(response.data.results);
} catch (error) {
console.error('Failed to fetch movies:', error);
setMovies([]);
}
};
const displayMovies = () => {
return movies.map((movie) => (
));
};
// ✅ 依赖项必须包含 listMovies,否则切换路由时不会重新请求
useEffect(() => {
getMovies();
}, [listMovies]); // ⚠️ 注意:这里应依赖 listMovies,而非 location!
// 动态标题优化(可选但推荐)
const getPageTitle = () => {
switch (listMovies) {
case 'now_playing': return 'Now Playing';
case 'top_rated': return 'Top Rated';
default: return 'Movies';
}
};
return (
<>
{getPageTitle()}
{displayMovies()}
>
);
}
export default Movielist;? 关键修正与最佳实践说明:
- useEffect 的依赖项必须是 [listMovies],而非 [location]。因为 listMovies 是由父路由明确传入的、决定数据源的唯一变量;location 对象本身在路由跳转时虽会变,但其变化并不直接反映业务逻辑差异,且可能因对象引用变化导致不必要的重复请求。
- useLocation() 在本例中非必需——除非你需要访问 location.search 或 location.state 等额外信息。当前场景下,listMovies 已完全承载路由语义,更简洁、更可控。
- 路由配置(App.js)保持原样即可,
} 已是标准且推荐的做法,符合“声明式路由 + 显式数据流”原则。 - 建议添加 try/catch 错误处理,提升健壮性;并用 switch 动态生成页面标题,增强可维护性。
✅ 最终效果:组件完全解耦、高度复用,同一 Movielist 可无缝支持任意 TMDB 列表端点(如未来扩展 /upcoming 或 /popular),只需在路由中传入对应字符串即可。











