组件渲染已触发,但 DOM 未更新
Posted
技术标签:
【中文标题】组件渲染已触发,但 DOM 未更新【英文标题】:Component render triggered, but DOM not updated 【发布时间】:2019-08-23 21:19:40 【问题描述】:我的第一个 React 应用程序出现问题。 在实践中,我有一个组件层次结构(我正在创建一个多媒体电影库),单击选项卡(由电影组件表示)必须显示单个电影的具体描述(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;
如果有人可以帮助我,我将不胜感激。我已经用了两天了,但我真的无法处理它
【问题讨论】:
【参考方案1】:这是因为在SingleMovieDetails
组件中,您将 props 值存储在 state 中,而不是在 props 更改时更新 state。 constructor
不会再次被调用,因此状态将始终具有初始值。
您有两种选择来解决这个问题:
直接使用 props 值而不是在 state 中存储数据(首选方式)。像这样:
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 变量。
【讨论】:
【参考方案2】:您的问题只与一个文件有关:SingleMovieDetails.js
在 constructor 中,您将组件状态设置为使用 props 进行初始化(第一次发送到组件)
但是在您的 render() 方法中,您再次引用了该 state:
<Movie size='big' movie=this.state.movie/>
总而言之,这并非完全错误,但您需要做以下两件事之一:
添加一个方法来使用 nextPropsReceived 更新你的组件状态(生命周期方法被调用:将接收道具,如果你使用的是最新版本,你应该使用:getDerivedStateFromProps)
首选选项:您不需要电影组件的状态,因此只需使用渲染函数中的道具(this.props.movie) 之后你也可以删除构造函数,因为里面没有什么特别的。 :)
编辑: 所以,在这里要明确一点:由于您只设置一次状态(构造函数不会在每次生命周期更新时调用),您将始终只保存第一个值。从外部更改 props 只会触发 render(),但不会再次启动构造函数;D
【讨论】:
以上是关于组件渲染已触发,但 DOM 未更新的主要内容,如果未能解决你的问题,请参考以下文章