我的第一个React应用程序遇到了问题。 实际上,我有一个组件层次结构(我正在创建一个多媒体电影画廊),单击选项卡(由Movie组件表示)时,这些组件必须显示单个电影的特定描述(SingleMovieDetails)。 问题在于,仅在第一次单击时更新DOM,然后即使SingleMovieDetails道具发生更改,DOM仍会锁定在第一个渲染的电影上。
这是我到目前为止编写的代码...
//Movie component
import React from "react";
import styles from "./Movie.module.scss";
import PropTypes from "prop-types";
class Movie extends React.Component{
constructor(props){
super(props);
this.imgUrl = `http://image.tmdb.org/t/p/w342/${this.props.movie.poster_path}`;
}
render(){
if(!this.props.size)
return <div onClick={this.props.callbackClick(this.props.movie.id)}
name={this.props.movie.id}
className={styles.movieDiv}
style={{backgroundImage: `url(${this.imgUrl})`}}></div>;
return <div onClick={() => this.props.callbackClick(this.props.movie.id)}
name={this.props.movie.id}
className={styles.movieDivBig}
style={{backgroundImage: `url(${this.imgUrl})`}}></div>;
}
}
Movie.propTypes = {
movie: PropTypes.any,
callbackClick: PropTypes.any
};
export default Movie;
SingleMovieDetails.js
import React from "react";
import styles from "./SingleMovieDetails.module.scss";
import Movie from "../Movie";
import SingleMovieDescription from "../SingleMovieDescription";
import MovieCast from "../MovieCast";
import SingleMovieRatings from "../SingleMovieRatings";
class SingleMovieDetails extends React.Component{
constructor(props){
super(props);
console.log(props);
this.state = props;
console.log('constructor', this.state.movie)
}
render(){
console.log('SMD', this.state.movie)
return (
<>
<div className={styles.container}>
<div className={styles.flayer}>
<Movie size={'big'} movie={this.state.movie}/>
</div>
<div className={styles.description}>
<SingleMovieDescription movie={this.state.movie}/>
<MovieCast></MovieCast>
</div>
<div className={styles.ratings}>
<SingleMovieRatings />
</div>
</div>
</>
);
}
}
export default SingleMovieDetails;
MovieCarousel.js
import React from "react";
import PropTypes from "prop-types";
import Movie from "../Movie";
import styles from "./MovieCarousel.module.scss";
import SingleMovieDetails from "../SingleMovieDetails";
class MovieCarousel extends React.Component {
constructor(props) {
super(props);
this.state = [];
this.callbackClickMovie = this.callbackClickMovie.bind(this);
}
callbackClickMovie(id) {
const singleMovieApi = `https://api.themoviedb.org/3/movie/${id}?api_key=b6f2e7712e00a84c50b1172d26c72fe9`;
fetch(singleMovieApi)
.then(function(response) {
return response.json();
})
.then(data => {
this.setState({ selected: data });
});
}
render() {
let details = null;
if (this.state.selected) {
details = <SingleMovieDetails movie={this.state.selected} />;
}
let counter = 6;
let movies = this.props.movies.map(el => {
let element = (
<Movie movie={el} callbackClick={this.callbackClickMovie} />
);
counter--;
if (counter >= 0) return element;
return;
});
let content = (
<>
<h2 className={styles.carouselTitle}>{this.props.title}</h2>
{movies}
{details}
</>
);
return content;
}
}
MovieCarousel.propTypes = {
children: PropTypes.any
};
export default MovieCarousel;
如果有人可以帮助我,我将非常感激。我已经待了两天了,但我实在无法应付
答案 0 :(得分:3)
您的问题仅与一个文件有关:SingleMovieDetails.js
在构造函数内部,您正在设置组件状态以使用道具进行初始化(第一次发送到组件)
但是在您的 render()方法中,您再次引用该状态:
<Movie size={'big'} movie={this.state.movie}/>
总而言之,这并不是完全错误,但是您需要执行以下两项操作之一:
添加一个使用nextPropsReceived更新组件状态的方法(称为生命周期方法:将接收道具,如果使用的是最新版本,则应使用:getDerivedStateFromProps)
首选选项:您不需要电影组件的状态,因此只需在render函数(this.props.movie)中使用props 之后,您还可以删除构造函数,因为里面没有特殊的东西。 :)
修改: 因此,在这里要澄清一下:由于只设置了一次状态(并非在每次生命周期更新中都调用构造函数),所以始终只保存第一个值。从外部更改道具只会触发render(),但不会再次启动构造函数; D
答案 1 :(得分:3)
这是因为在SingleMovieDetails
组件中,您正在以状态存储props值,而不是在props更改时更新状态。 constructor
将不会再被调用,因此状态将始终具有初始值。
您可以通过两种方法解决此问题:
直接使用props值,而不是以状态(首选方式)存储数据。像这样:
class SingleMovieDetails extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<>
<div className={styles.container}>
<div className={styles.flayer}>
<Movie size={'big'} movie={this.props.movie}/>
</div>
<div className={styles.description}>
<SingleMovieDescription movie={this.props.movie}/>
<MovieCast></MovieCast>
</div>
<div className={styles.ratings}>
<SingleMovieRatings />
</div>
</div>
</>
);
}
}
使用getDerivedStateFromProps,并在道具更改时更新状态值。
与Movie
组件相同的问题,请将此行放入render方法中,否则它将始终显示相同的图像:
const imgUrl = `http://image.tmdb.org/t/p/w342/${this.props.movie.poster_path}`
并使用此imgUrl变量。