【问题标题】:Props array from async parent component undefined when in componentDidMount in child component在子组件中的 componentDidMount 中未定义来自异步父组件的道具数组
【发布时间】:2020-07-24 22:08:13
【问题描述】:

我正在使用 spotify API 来检索一个名为 track 的对象,该对象显示歌曲的名称和艺术家的名称。曲目的名称是一个字符串,但艺术家是一个对象数组。

我能够检索信息的唯一方法是,如果我创建另一个函数来通过单击按钮来调用将道具存储在状态中,但我希望道具信息以状态存储而无需单击按钮.

这是每个单独的曲目:

import React from 'react';
import PropTypes from 'prop-types';
import './Tracks.css';

class Track extends React.Component{
    constructor(props){
        console.log(props);
        super(props);
        this.state={
            artist: ''
        }
        // this.displayArtists = this.displayArtists.bind(this);
        this.componentDidMount = this.componentDidMount.bind(this);
    }

    // displayArtists(){

    //     this.setState({artist: this.props.artists[0].name});
    //     console.log(this.props);

    // }
    componentDidMount(){
        this.setState({artist: this.props.artists[0].name});
    }

    render(){
        return(
            <div className="track" style={{display: 'flex', backgroundColor: "gray", border: '1px solid black', borderRadius: '5px', margin:'5px'}}>
                <h1 className="tracktitle" style={{height: 45, fontSize: 25}}>{this.props.title}</h1>
                <p style={{fontSize: 15}}>by {this.state.artist}</p>
                <button >display</button>
            </div>
        ); 
    }
}

export default Track;

Track.propTypes = {
    title: PropTypes.string,
    artists: PropTypes.array
  };

这是我从 (TracksPage.js) 发送道具的地方:

....
  async componentDidMount(){
        spotifyApi.setAccessToken(localStorage.getItem('access_token'));
        // console.log('accesstoken', localStorage.getItem('access_token'));
        let tracks = await spotifyApi.getMyTopTracks();

        tracks.items.forEach(track => this.setState(prevState => ({
            tracks: [... prevState.tracks, {name: track.name, artist: track.artists}]
        })));

        this.setState({ tracks: this.state.tracks.slice(1) })

        // this.state.tracks.forEach(track => console.log(track.artists.name ));
        // this.state.tracks.forEach(track => this.setState({artist: track.artists[0].name}));
    }

    render(){
        return(
        <div>
            <h1>My Spotify React App!</h1>
            <div className="tracks-container" style={{maxHeight: 500, overflow: 'scroll', margin:50, marginTop:25}}>
            
            {this.state.tracks.map((track => 
                <Track key={track.id} title={track.name} artists={track.artist}/>
            ))}
            </div>
        </div>
        );
    };
}

当我在构造函数调用期间控制台记录道具时,数据会显示,但当我在 componentDidMount() 中调用它时不会显示。轨道的名称可以正常工作,但即使两个道具一起发送,只有艺术家对象数组不能。

【问题讨论】:

    标签: javascript reactjs spotify


    【解决方案1】:

    尝试使用 componentWillReceiveProps 而不是使用 componentDidMount

      componentWillReceiveProps(nextProps) {
    if (nextProps.props.artists) {
          this.setState({
             this.setState({artist:nextProps.artists[0].name});
          });
        }
    }
    

    【讨论】:

      【解决方案2】:

      我认为这是你的问题:

      artist: this.props.artists[0].name
      

      “艺术家”道具会将艺术家数组从轨道状态传递到您制作的轨道组件。您在 Track 组件上将状态设置为“艺术家”,但如果我的想法正确,您不需要 .name。当您传递它时,您已经拥有了一系列艺术家(我认为当它实际上是一系列艺术家时,您称该州为“艺术家”是被欺骗了。

      tracks: [... prevState.tracks, {name: track.name, artist: track.artists}]
      

      尝试从 Tracks 组件中的 setState 调用中删除 .name,它应该会从艺术家数组中获取第一个艺术家(索引为 0 的艺术家)。

      您可能还想将我突出显示的第二行重写为artists: tracks.artists,这样就不会那么混乱了。

      让我知道这是否有效!

      【讨论】:

        【解决方案3】:

        从您发布的内容来看,除非父组件状态更新,否则艺术家状态似乎不会改变,因此没有理由在您的轨道组件中使用状态。最好直接使用道具。

        简单地做:

        render(){
          const artistName = this.props.artists[0].name;
          return(
            <div className="track" style={{display: 'flex', backgroundColor: "gray", border: '1px solid black', borderRadius: '5px', margin:'5px'}}>
              <h1 className="tracktitle" style={{height: 45, fontSize: 25}}>{this.props.title}</h1>
              <p style={{fontSize: 15}}>by {artistName}</p>
              <button >display</button>
            </div>
          );
        }
        

        您还通过 forEach 调用强制跟踪页面组件不必要地重新渲染。您可以通过以下方式一次添加所有新曲目:

        async componentDidMount(){
          spotifyApi.setAccessToken(localStorage.getItem('access_token'));
          let newTracks = await spotifyApi.getMyTopTracks();
        
          this.setState(prevState => ({
            tracks: [
              ...prevState.tracks,
              ...newTracks.items.map(track => ({
                id: track.id, 
                name: track.name,
                artist: track.artists
              }))
            ]
          });
        }
        

        注意在最后一个 sn-p 中添加的 id 属性。映射轨道时,您使用 id 道具作为键。键是唯一的至关重要,如果它们都未定义,您将得到错误。

        为了可读性,值得使用artistartists。同时使用这两种方法会使您容易出现难以调试的拼写错误。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-04-24
          • 2020-08-25
          • 2020-08-04
          • 2019-12-09
          • 1970-01-01
          • 2023-03-05
          • 1970-01-01
          相关资源
          最近更新 更多