React中如何向其他组件传递数据:电影站点详情页传参问题
修复方案
核心问题梳理
- 影片详情拉取逻辑仅绑定在爱心图标上,用户点击海报跳转时不会触发详情接口请求,
content一直为空初始值,无法传递有效数据 - 通过
NavLink的state传递的参数不会直接作为详情页组件的props传入,需要从路由的location对象读取 - 影片视频链接的拉取逻辑直接写在组件顶层,会触发无限重渲染,严重影响性能
content初始值设为数组,但接口返回的是电影对象,会引发后续取值报错
具体修改步骤
1. 调整MovieCard组件逻辑
推荐直接传递电影ID到详情页,由详情页自行拉取详情数据,避免跳转时接口还未返回导致数据丢失的问题,修改后代码如下:
import React, {useState, useEffect} from 'react' import placeholder from '../Assets/Placeholder.jpg' import {Button, Nav} from 'react-bootstrap' import '../sass/custom.scss' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faStar, faPlay, faHeart, faShare } from '@fortawesome/free-solid-svg-icons' import {NavLink} from 'react-router-dom'; export const MovieCard = ({movieresults}) => { const [trailer, setTrailer] = useState(); // 把视频拉取逻辑放到useEffect中,避免无限重渲染 useEffect(() => { fetch(`https://api.themoviedb.org/3/movie/${movieresults.id}/videos?api_key=${process.env.REACT_APP_TMDB_KEY}&language=en-US`) .then((res) => res.json()) .then((data) => { if (!data.errors) { setTrailer(data.results[0]?.key); } }) }, [movieresults.id]) // 爱心点击逻辑保留 const onClick = e => { fetch(`https://api.themoviedb.org/3/movie/${movieresults.id}?api_key=${process.env.REACT_APP_TMDB_KEY}&language=en-US`) .then((res) => res.json()) .then((data) => { if (!data.errors) { console.log(data) } }) } return ( <div className="movie-card"> <div className="poster-container"> <span className="rating translate-middle rounded-pill"> <FontAwesomeIcon icon={faStar} className="star"/> {movieresults.vote_average} </span> {movieresults.poster_path ? ( // 直接传递电影ID到详情页 <Nav.Link as={NavLink} exact={true} to={{pathname:"/film", state: { movieId: movieresults.id } }} className="poster-link" > <img className="poster" src={`https://image.tmdb.org/t/p/w300${movieresults.poster_path}`} alt= {movieresults.title} /> </Nav.Link> ) : ( <img className="poster" src={placeholder} alt= {movieresults.title} /> )} </div> <div className="content-container"> <b className="title mobile-text">{movieresults.title}</b> <p className="desc mobile-text">{movieresults.release_date}</p> <div className="card-btn"> <Button className="btn btn-secondary watch-btn" target="__blank" href={`https://www.youtube.com/watch?v=${trailer}`}><FontAwesomeIcon icon={faPlay} /> Trailer</Button> <div className="icons"> <a href className="icon-btn"><FontAwesomeIcon icon={faHeart} onClick={onClick}/> </a> <a href className="icon-btn"><FontAwesomeIcon icon={faShare} /> </a> </div> </div> </div> </div> ) }
2. 调整FilmPage详情页逻辑
引入useLocation钩子读取路由传递的电影ID,在详情页拉取影片详情数据:
import React, {useState, useEffect} from 'react' import { Container } from 'react-bootstrap'; import { useLocation } from 'react-router-dom'; export const FilmPage = () => { const location = useLocation(); const [content, setContent] = useState({}); const movieId = location.state?.movieId; useEffect(() => { if (!movieId) return; // 详情页自行拉取影片数据 fetch(`https://api.themoviedb.org/3/movie/${movieId}?api_key=${process.env.REACT_APP_TMDB_KEY}&language=en-US`) .then((res) => res.json()) .then((data) => { if (!data.errors) { setContent(data); } }) }, [movieId]) return ( <Container> <h1>Film Page</h1> {content.id && <h1>{content.id}</h1>} </Container> ) }
补充说明
如果你确实需要在卡片组件拉取数据后再传递到详情页,需要将点击跳转逻辑替换为手动触发:先调用详情拉取接口,接口返回成功后再调用useNavigate钩子跳转页面,同时把数据放到state中,避免跳转时数据还未返回的问题。
内容的提问来源于stack exchange,提问作者Imad
相关产品推荐
相关产品推荐

