【问题标题】:Component render triggered, but DOM not updated组件渲染已触发,但 DOM 未更新
【发布时间】: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;

如果有人可以帮助我,我将不胜感激。我已经用了两天了,但我真的无法处理它

【问题讨论】:

    标签: reactjs ecmascript-2017


    【解决方案1】:

    这是因为在SingleMovieDetails 组件中,您将 props 值存储在 state 中,而不是在 props 更改时更新 state。 constructor 不会再次被调用,因此状态将始终具有初始值。

    您有两种选择来解决这个问题:

    1. 直接使用 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>
           </>
          );
        }
      }
      
    2. 使用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}/>
      

      总而言之,这并非完全错误,但您需要做以下两件事之一:

      1. 添加一个方法来使用 nextPropsReceived 更新你的组件状态(生命周期方法被调用:将接收道具,如果你使用的是最新版本,你应该使用:getDerivedStateFromProps)

      2. 首选选项:您不需要电影组件的状态,因此只需使用渲染函数中的道具(this.props.movi​​e) 之后你也可以删除构造函数,因为里面没有什么特别的。 :)

      编辑: 所以,在这里要明确一点:由于您只设置一次状态(构造函数不会在每次生命周期更新时调用),您将始终只保存第一个值。从外部更改 props 只会触发 render(),但不会再次启动构造函数;D

      【讨论】:

        猜你喜欢
        • 2020-05-03
        • 2017-05-20
        • 1970-01-01
        • 2018-12-04
        • 2020-12-16
        • 1970-01-01
        • 2020-08-18
        • 2021-12-01
        • 2021-01-18
        相关资源
        最近更新 更多