React中如何跨页面传递收藏电影数组至收藏页
问题根源
- 你的
favouriteMovies状态定义在Home组件内部,属于组件级私有状态:- 切换路由离开Home页面时,Home组件会被卸载,存在这里的收藏数据会直接丢失
Favourites组件和Home是平级路由,无法直接访问Home的内部状态
- 原有
handleFavourites逻辑不符合React状态更新规则:直接用push修改原state数组不会触发React重渲染,页面不会同步更新,必须通过setFavouriteMovies生成新数组才能驱动视图更新。
解决方法(状态提升,零额外依赖)
把收藏相关的状态和操作方法提升到两个路由的公共父组件App.js中,再通过props把状态和方法传给需要的子组件,这是React官方推荐的跨平级组件共享状态方案。
第一步:修改App.js
把收藏状态、收藏操作方法都定义在App层,传给对应路由组件:
import React, { useState } from "react"; import Header from "./Header"; import {Route, Routes} from 'react-router-dom' import Favourites from "./views/Favourites"; import Home from "./views/Home"; import About from "./views/About"; function App() { // 收藏状态提升到公共父组件 const [favouriteMovies, setFavouriteMovies] = useState([]) // 修正收藏逻辑:通过set方法生成新数组触发渲染,加去重逻辑避免重复收藏 const handleAddFavourite = (movie) => { setFavouriteMovies(prev => { const isCollected = prev.some(item => item.imdbID === movie.imdbID) if(isCollected) return prev return [...prev, movie] }) } // 收藏页需要的取消收藏方法 const handleRemoveFavourite = (movieId) => { setFavouriteMovies(prev => prev.filter(item => item.imdbID !== movieId)) } return ( <> <Header /> <div> <Routes> {/* 给首页传添加收藏的方法 */} <Route path="/" element={<Home handleAddFavourite={handleAddFavourite} />} /> {/* 给收藏页传收藏列表、取消收藏方法 */} <Route path="/favourites" element={<Favourites favouriteMovies={favouriteMovies} handleRemoveFavourite={handleRemoveFavourite} />} /> <Route path="/about" element={<About />} /> </Routes> </div> </> ) } export default App;
第二步:修改Home.js
删除Home内部定义的收藏状态和错误的收藏方法,改用父组件传入的方法:
import React, { useState, useEffect } from 'react'; import SearchField from '../components/SearchField'; import MovieList from '../components/MovieList'; // 接收父组件传入的添加收藏方法 const Home = ({ handleAddFavourite }) => { const [movies, setMovies] = useState([]); const [searchInput, setSearchInput] = useState ('') // 删除原Home内部的favouriteMovies状态、错误的handleFavourites方法 const getMovies = async (searchInput) => { const url = `http://www.omdbapi.com/?s=${searchInput}&apikey=87aa1413`; const res = await fetch(url); const resJson = await res.json(); if (resJson.Search){ setMovies(resJson.Search) } }; useEffect(() => { getMovies(searchInput); }, [searchInput]); return ( <> <SearchField searchInput={searchInput} setSearchInput={setSearchInput} /> {/* 把收藏方法传给电影列表组件 */} <MovieList movies = {movies} handleFavourites = {handleAddFavourite}/> </> ) } export default Home;
第三步:修改Favourites.js
接收父组件传入的收藏列表,渲染内容即可:
import React from "react" // 接收父组件传入的收藏列表、取消收藏方法 const Favourites = ({ favouriteMovies, handleRemoveFavourite }) => { return ( <> <h1>我的收藏</h1> <div className="favourite-list"> {favouriteMovies.length === 0 ? ( <p>暂无收藏电影</p> ) : ( favouriteMovies.map(movie => ( <div key={movie.imdbID} className="movie-card"> <img src={movie.Poster} alt={movie.Title} /> <p>{movie.Title} ({movie.Year})</p> <button onClick={() => handleRemoveFavourite(movie.imdbID)}>取消收藏</button> </div> )) )} </div> </> ) } export default Favourites;
扩展可选方案
如果后续项目组件层级变深,多层props传递太繁琐,可以根据项目规模选择其他方案:
- 用React Context做全局状态容器,适合中小型项目,无需安装额外依赖
- 用Zustand、Redux等轻量/标准状态管理库,适合大型项目,全局状态访问更灵活
- 如果需要刷新页面收藏不丢失,可以在状态更新时同步把收藏列表存入
localStorage,初始化状态时优先从本地缓存读取即可。
核心注意点:React状态更新不能直接修改原数组/对象,必须返回新的引用值,React才能检测到状态变化触发重渲染。
内容的提问来源于stack exchange,提问作者awaltherrr
相关产品推荐
相关产品推荐

