首页 > 解决方案 > 如何更新组件之间的数据?

问题描述

控制台的图像我正在尝试使用电影 DB API 创建一个网站。我创建了一个包含一些电影的轮播,并希望通过单击电影海报来打开一个包含有关电影的全面信息的新页面。我正在使用 componentDidMount 在一个组件中获取数据以创建 UI,并将电影 ID 传递给另一个组件,在该组件中我使用 componentWillReceiveProps 通过使用 ID 获取另一个数据。它一直有效,直到我开始使用状态,所以现在它在我点击电影海报之前在控制台中显示两个数组,当我点击海报时,它会显示一个数组并从 API 加载电影数据,然后如果我点击另一个海报它使用上一部电影和当前电影加载两个不同的对象。我发现 componentWillReceiveProps 使用起来很危险,但 componentDidUpdate 的工作方式相同。主要思想是,当用户点击海报时,它会获取其 id 并将其发送到另一个组件,其中 id 转到包含有关电影的完整信息的链接。有什么模式可以实现吗?

class Data extends Component {
  state = {
    movies: [],
    movieId: null
  };

  onClick = e => {
    this.setState({
      movieId: e.target.id
    });
    console.log(e.target.id);
  };

  componentDidMount() {
    fetch(url)
      .then(res => res.json())
      .then(data => {
        let movies = data.results.map(item => {
          return (
            <Link to="/movieInfo"> 
                <div className="overlay" onClick={this.onClick}>
                  <img
                    src= 
                    {`https://image.tmdb.org/t/p/w500/${item.poster_path}`}
                    alt={item.title}
                    id={item.id}
                   />
                </div>
              </Link> 
             );
        });

        this.setState({
          movies: movies
        });
      })
      .catch(err => console.log(err));
  }

render() {
    const { movies, movieId } = this.state;

    return (
      <div className="carousel">
        <Slider movie={movies} />
        <div className="notShow">
          <AdditionalInfo id={movieId} />
        </div>
      </div>
    );
  }
}




class AdditionalInfo extends Component {
  state = {
    movie: []
  };
  componentDidUpdate(prevProps) {
    if (prevProps.id !== null && prevProps.id !== this.props.id) {
      fetch(
        `https://api.themoviedb.org/3/movie/${
          prevProps.id
        }?api_key=81f382d33088c6d52099a62eab51d967&language=en-US`
      )
        .then(res => res.json())
        .then(data =>
          this.setState({
            movie: data
          })
        );
    } else {
      return null;
    }
  }
  render() {
    const { movie } = this.state;
    console.log(movie);
    return (
      <div className="movieInfo-container">
        {/* <section className="title" />
        <section className="cast">{movie.id}</section> */}
        work
      </div>
    );
  }
}
let movieArr = [];

class Slider extends Component {
  state = {
    currentIndex: 0,
    translateValue: 0
  };

  createNestedArr = () => {
    while (this.props.movie.length) {
      movieArr.push(this.props.movie.splice(0, 5));
    }
    return movieArr.map((item, i) => {
      return <Slide key={i} movieGroup={item} />;
    });
  };

  nextPic = () => {
    if (this.state.currentIndex === movieArr.length - 1) {
      return this.setState({
        currentIndex: 0,
        translateValue: 0
      });
    }
    this.setState(prevState => ({
      currentIndex: prevState.currentIndex + 1,
      translateValue: prevState.translateValue - this.slideWidth()
    }));
  };

  prevPic = () => {
    if (this.state.currentIndex === movieArr.length + 1) {
      return this.setState({
        currentIndex: 0,
        translateValue: 0
      });
    } else if (this.state.currentIndex === 0) {
      return this.setState({
        currentIndex: 0,
        translateValue: 0
      });
    }
    this.setState(prevState => ({
      currentIndex: prevState.currentIndex - 1,
      translateValue: prevState.translateValue + this.slideWidth()
    }));
  };

  slideWidth = () => {
    return document.querySelector(".new-releases-slide").clientWidth;
  };

  render() {
    return (
      <React.Fragment>
        <div
          className="movie-carousel"
          style={{
            transform: `translateX(${this.state.translateValue}px)`,
            transition: "transform ease-out 0.45s"
          }}
        >
          {this.createNestedArr()}
        </div>
        <LeftArrow prevPic={this.prevPic} />
        <RightArrow nextPic={this.nextPic} />
      </React.Fragment>
    );
  }
}

const Slide = props => {
  const { movieGroup } = props;
  return <div className="new-releases-slide">{movieGroup}</div>;
};

标签: reactjs

解决方案


componentDidMount在您的AdditionalIno组件中使用。您需要将点击的电影的 id 传递给MovieInfo组件。这<Link to="/movieInfo">需要<Link to={'/movieInfo/${item.id}'}>在您的MovieInfo组件中使用const { id } = this.props.match.params;.

import React, { Component } from 'react';
import Loader from "react-loader-spinner";

class AdditionalInfo extends Component {

  state = {
    movie: [],
    isLoading: true,
  };

  componentDidMount = () => {
    const { id } = this.props;

    if (!id) {
      return;
    }

    fetch(
      `https://api.themoviedb.org/3/movie/${id}?api_key=81f382d33088c6d52099a62eab51d967&language=en-US`
    )
      .then(res => res.json())
      .then(data =>
        this.setState({
          movie: data,
          isLoading: false,
        })
      );

  }

  render() {
    const { movie } = this.state;
    return (
      <div className="movieInfo-container">
        {this.state.isLoading

          ? <Loader type="Puff" color="#00BFFF" height="100" width="100" />
          : <div><section className="title" />
            <h1>{movie.title}</h1>
            <section className="cast">ID: {movie.id}</section>
            <h2>Overview</h2>
            <p>{movie.overview}</p></div>

        }
      </div>
    );
  }
}

export default AdditionalInfo;

然后在您的Data组件中更改您的componentDidMount

componentDidMount = () => {

  fetch(url)
    .then(res => res.json())
    .then(data => {
      let movies = data.results.map(item => {
        return (
          <Link to={`/movieInfo/${item.id}`}> 
              <div className="overlay" onClick={this.onClick}>
                <img
                  src= 
                  {`https://image.tmdb.org/t/p/w500/${item.poster_path}`}
                  alt={item.title}
                  id={item.id}
                />
              </div>
            </Link> 
          );
      });

      this.setState({
        movies: movies
      });
    })
    .catch(err => console.log(err));
}

在你MovieInfo做类似的事情

class MovieInfo extends Component {

  render() {
    const {id} = this.props.match.params;
    return (
      <div>
        <AdditionalInfo id={id} />
      </div>
    )
  }
}

你的路由器应该像

<Route path="/movieInfo/:id" exact component={MovieInfo} />

工作演示


推荐阅读