首页 > 解决方案 > 在子组件中的componentDidMount中未定义来自异步父组件的道具数组

问题描述

我正在使用 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() 中调用它时不会显示。轨道的名称可以正常工作,但即使两个道具一起发送,只有艺术家的对象数组不能。

标签: javascriptreactjsspotify

解决方案


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

只需这样做:

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 调用强制 trackpage 组件不必要地重新渲染。您可以一次添加所有新曲目,例如:

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
      }))
    ]
  });
}

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

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


推荐阅读