触发组件渲染,但 DOM 未更新
Component render triggered, but DOM not updated
我的第一个 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;
如果有人能帮助我,我将不胜感激。我已经用了两天了,但我真的无法处理它
您的问题只与一个文件有关:SingleMovieDetails.js
在 构造函数 中,您将组件状态设置为使用 props 进行初始化(第一次发送到组件)
但是在您的 render() 方法中,您再次引用了 state:
<Movie size={'big'} movie={this.state.movie}/>
总而言之,这并非完全错误,但您需要做以下两件事之一:
添加一个方法来使用 nextPropsReceived 更新您的组件状态(生命周期方法被调用:将接收道具,如果您使用的是最新版本,您应该使用:getDerivedStateFromProps)
首选选项:你不需要电影组件的状态,所以只需使用渲染函数中的道具(this.props.movie)
之后你也可以删除构造函数,因为里面没有什么特别的。 :)
编辑:
所以,这里要明确一点:因为你只设置一次状态(构造函数不会在每次生命周期更新时调用),你将始终只保存第一个值。从外部更改 props 只会触发 render(),但不会再次启动构造函数;D
这是因为在 SingleMovieDetails
组件中,您将道具值存储在状态中,而不是在道具更改时更新状态。 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
组件也有同样的问题,将此行放在渲染方法中,否则它将始终显示相同的图像:
const imgUrl = `http://image.tmdb.org/t/p/w342/${this.props.movie.poster_path}`
并使用这个 imgUrl 变量。
我的第一个 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;
如果有人能帮助我,我将不胜感激。我已经用了两天了,但我真的无法处理它
您的问题只与一个文件有关:SingleMovieDetails.js
在 构造函数 中,您将组件状态设置为使用 props 进行初始化(第一次发送到组件)
但是在您的 render() 方法中,您再次引用了 state:
<Movie size={'big'} movie={this.state.movie}/>
总而言之,这并非完全错误,但您需要做以下两件事之一:
添加一个方法来使用 nextPropsReceived 更新您的组件状态(生命周期方法被调用:将接收道具,如果您使用的是最新版本,您应该使用:getDerivedStateFromProps)
首选选项:你不需要电影组件的状态,所以只需使用渲染函数中的道具(this.props.movie) 之后你也可以删除构造函数,因为里面没有什么特别的。 :)
编辑: 所以,这里要明确一点:因为你只设置一次状态(构造函数不会在每次生命周期更新时调用),你将始终只保存第一个值。从外部更改 props 只会触发 render(),但不会再次启动构造函数;D
这是因为在 SingleMovieDetails
组件中,您将道具值存储在状态中,而不是在道具更改时更新状态。 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
组件也有同样的问题,将此行放在渲染方法中,否则它将始终显示相同的图像:
const imgUrl = `http://image.tmdb.org/t/p/w342/${this.props.movie.poster_path}`
并使用这个 imgUrl 变量。