简体   繁体   English

组件渲染已触发,但DOM未更新

[英]Component render triggered, but DOM not updated

I'm having problems with my first React application. 我的第一个React应用程序遇到了问题。 In practice, I have a hierarchy of components (I'm creating a multimedia film gallery) which, upon clicking on a tab (represented by the Movie component) must show the specific description of the single film (SingleMovieDetails). 实际上,我有一个组件层次结构(我正在创建一个多媒体电影画廊),单击选项卡(由Movie组件表示)时,这些组件必须显示单个电影的特定描述(SingleMovieDetails)。 The problem is that the DOM is updated only on the first click, then even if the SingleMovieDetails props change, the DOM remains locked on the first rendered movie. 问题在于,仅在第一次单击时更新DOM,然后即使SingleMovieDetails道具发生更改,DOM仍会锁定在第一个渲染的电影上。

Here's the code i wrote so far... 这是我到目前为止编写的代码...

//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 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 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;

I would be really grateful if someone could help me. 如果有人可以帮助我,我将不胜感激。 I have been on it for two days but I can't really deal with it 我已经待了两天了,但我实在无法应付

your Problem is just related to one file: SingleMovieDetails.js 您的问题仅与一个文件有关:SingleMovieDetails.js

Inside the constructor you´re setting the component state to get initialized with the props (send to the component the first time) 构造函数中,您正在设置组件状态以使用props进行初始化(首次发送到组件)

But inside your render() method you are referencing that state again: 但是在您的render()方法内部,您再次引用了该状态

<Movie size={'big'} movie={this.state.movie}/>

All in all thats not completely wrong, but you need to do one of two things: 总而言之,这并不是完全错误,但是您需要执行以下两项操作之一:

  1. Add a method to update your component state with the nextPropsReceived (Lifecycle Method was called: will receive props, if you are using the latest version you should use: getDerivedStateFromProps) 添加一个使用nextPropsReceived更新组件状态的方法(称为生命周期方法:将接收道具,如果使用的是最新版本,则应使用:getDerivedStateFromProps)

  2. preferred option : you dont need a state for the movie component, so just use the props inside the render function (this.props.movie) afterwards you can also delete the constructor, because there is nothing special inside. 首选选项 :影片组件不需要状态,因此之后只需在render函数(this.props.movi​​e)中使用props,就可以删除构造函数,因为里面没有特殊的东西。 :) :)

edit: So, just to be clear here: Since you´re only setting the state once (the constructor is not called on every lifecycle update) you will always only have the first value saved. 编辑:所以,这里要澄清一下:由于只设置了一次状态(并非在每次生命周期更新中都调用构造函数),所以始终只保存第一个值。 Changing props from outside will just trigger render(), but wont start the constructor again ;D 从外部更改道具只会触发render(),但不会再次启动构造函数; D

This is because in SingleMovieDetails component, you are storing the props values in state and not updating the state on props change. 这是因为在SingleMovieDetails组件中,您是在状态中存储道具值,而不是在道具更改时更新状态。 constructor will not get called again so state will always have the initial values. constructor不会再次被调用,因此state始终具有初始值。

You have two options to solve the issue: 您有两种选择来解决此问题:

  1. Directly use the props values instead of storing data in state (preferred way). 直接使用props值,而不是以状态(首选方式)存储数据。 Like this: 像这样:

     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. Use getDerivedStateFromProps , and update the state value on props change. 使用getDerivedStateFromProps ,并在更改道具时更新状态值。

Same issue with Movie component also, put this line in the render method, otherwise it will always show same image: Movie组件也存在相同的问题,请将此行放入render方法中,否则它将始终显示相同的图像:

const imgUrl = `http://image.tmdb.org/t/p/w342/${this.props.movie.poster_path}`

And use this imgUrl variable. 并使用此imgUrl变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM