reactjs - 如何更新组件之间的数据?
问题描述
控制台的图像我正在尝试使用电影 DB API 创建一个网站。我创建了一个包含一些电影的轮播,并希望通过单击电影海报来打开一个包含有关电影的全面信息的新页面。我正在使用 componentDidMount 在一个组件中获取数据以创建 UI,并将电影 ID 传递给另一个组件,在该组件中我使用 componentWillReceiveProps 通过使用 ID 获取另一个数据。它一直有效,直到我开始使用状态,所以现在它在我点击电影海报之前在控制台中显示两个数组,当我点击海报时,它会显示一个数组并从 API 加载电影数据,然后如果我点击另一个海报它使用上一部电影和当前电影加载两个不同的对象。我发现 componentWillReceiveProps 使用起来很危险,但 componentDidUpdate 的工作方式相同。主要思想是,当用户点击海报时,它会获取其 id 并将其发送到另一个组件,其中 id 转到包含有关电影的完整信息的链接。有什么模式可以实现吗?
class Data extends Component {
state = {
movies: [],
movieId: null
};
onClick = e => {
this.setState({
movieId: e.target.id
});
console.log(e.target.id);
};
componentDidMount() {
fetch(url)
.then(res => res.json())
.then(data => {
let movies = data.results.map(item => {
return (
<Link to="/movieInfo">
<div className="overlay" onClick={this.onClick}>
<img
src=
{`https://image.tmdb.org/t/p/w500/${item.poster_path}`}
alt={item.title}
id={item.id}
/>
</div>
</Link>
);
});
this.setState({
movies: movies
});
})
.catch(err => console.log(err));
}
render() {
const { movies, movieId } = this.state;
return (
<div className="carousel">
<Slider movie={movies} />
<div className="notShow">
<AdditionalInfo id={movieId} />
</div>
</div>
);
}
}
class AdditionalInfo extends Component {
state = {
movie: []
};
componentDidUpdate(prevProps) {
if (prevProps.id !== null && prevProps.id !== this.props.id) {
fetch(
`https://api.themoviedb.org/3/movie/${
prevProps.id
}?api_key=81f382d33088c6d52099a62eab51d967&language=en-US`
)
.then(res => res.json())
.then(data =>
this.setState({
movie: data
})
);
} else {
return null;
}
}
render() {
const { movie } = this.state;
console.log(movie);
return (
<div className="movieInfo-container">
{/* <section className="title" />
<section className="cast">{movie.id}</section> */}
work
</div>
);
}
}
let movieArr = [];
class Slider extends Component {
state = {
currentIndex: 0,
translateValue: 0
};
createNestedArr = () => {
while (this.props.movie.length) {
movieArr.push(this.props.movie.splice(0, 5));
}
return movieArr.map((item, i) => {
return <Slide key={i} movieGroup={item} />;
});
};
nextPic = () => {
if (this.state.currentIndex === movieArr.length - 1) {
return this.setState({
currentIndex: 0,
translateValue: 0
});
}
this.setState(prevState => ({
currentIndex: prevState.currentIndex + 1,
translateValue: prevState.translateValue - this.slideWidth()
}));
};
prevPic = () => {
if (this.state.currentIndex === movieArr.length + 1) {
return this.setState({
currentIndex: 0,
translateValue: 0
});
} else if (this.state.currentIndex === 0) {
return this.setState({
currentIndex: 0,
translateValue: 0
});
}
this.setState(prevState => ({
currentIndex: prevState.currentIndex - 1,
translateValue: prevState.translateValue + this.slideWidth()
}));
};
slideWidth = () => {
return document.querySelector(".new-releases-slide").clientWidth;
};
render() {
return (
<React.Fragment>
<div
className="movie-carousel"
style={{
transform: `translateX(${this.state.translateValue}px)`,
transition: "transform ease-out 0.45s"
}}
>
{this.createNestedArr()}
</div>
<LeftArrow prevPic={this.prevPic} />
<RightArrow nextPic={this.nextPic} />
</React.Fragment>
);
}
}
const Slide = props => {
const { movieGroup } = props;
return <div className="new-releases-slide">{movieGroup}</div>;
};
解决方案
componentDidMount
在您的AdditionalIno
组件中使用。您需要将点击的电影的 id 传递给MovieInfo
组件。这<Link to="/movieInfo">
需要<Link to={'/movieInfo/${item.id}'}>
在您的MovieInfo
组件中使用const { id } = this.props.match.params;
.
import React, { Component } from 'react';
import Loader from "react-loader-spinner";
class AdditionalInfo extends Component {
state = {
movie: [],
isLoading: true,
};
componentDidMount = () => {
const { id } = this.props;
if (!id) {
return;
}
fetch(
`https://api.themoviedb.org/3/movie/${id}?api_key=81f382d33088c6d52099a62eab51d967&language=en-US`
)
.then(res => res.json())
.then(data =>
this.setState({
movie: data,
isLoading: false,
})
);
}
render() {
const { movie } = this.state;
return (
<div className="movieInfo-container">
{this.state.isLoading
? <Loader type="Puff" color="#00BFFF" height="100" width="100" />
: <div><section className="title" />
<h1>{movie.title}</h1>
<section className="cast">ID: {movie.id}</section>
<h2>Overview</h2>
<p>{movie.overview}</p></div>
}
</div>
);
}
}
export default AdditionalInfo;
然后在您的Data
组件中更改您的componentDidMount
componentDidMount = () => {
fetch(url)
.then(res => res.json())
.then(data => {
let movies = data.results.map(item => {
return (
<Link to={`/movieInfo/${item.id}`}>
<div className="overlay" onClick={this.onClick}>
<img
src=
{`https://image.tmdb.org/t/p/w500/${item.poster_path}`}
alt={item.title}
id={item.id}
/>
</div>
</Link>
);
});
this.setState({
movies: movies
});
})
.catch(err => console.log(err));
}
在你MovieInfo
做类似的事情
class MovieInfo extends Component {
render() {
const {id} = this.props.match.params;
return (
<div>
<AdditionalInfo id={id} />
</div>
)
}
}
你的路由器应该像
<Route path="/movieInfo/:id" exact component={MovieInfo} />
推荐阅读
- jquery - 为什么柏树调用动画甚至调用都不起作用?
- c++ - 将字符串拆分为向量
- android - 如何获取 Unitech PA760 的 Android SDK?
- c# - EF6 与 MySQL - 日期时间中的格式异常
- python - Django 应用程序的错误配置错误
- ios - 弹出 iOS UINavigationController 时如何调用方法?
- html - 孩子不尊重其父母的大小 SwiftUI
- linux - .Net Core 3.1 是否具有检测 GPIO 引脚更改的事件驱动方法?
- python - 如何在python的polyglot中用本地目录覆盖下载器目录
- angular-material - Angular 材质表为每条记录增加一行,同时实现 Angular 9 中的行代码扩展