javascript - 在子组件中的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() 中调用它时不会显示。轨道的名称可以正常工作,但即使两个道具一起发送,只有艺术家的对象数组不能。
解决方案
从您发布的内容来看,除非父组件状态更新,否则艺术家状态似乎不会改变,因此没有理由在您的轨道组件中使用状态。最好直接使用道具。
只需这样做:
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 道具作为键。键是唯一的至关重要,如果它们都未定义,您将得到错误。
值得使用artist
或artists
提高可读性。同时使用这两种方法会使您容易出现难以调试的拼写错误。
推荐阅读
- python - Pandas - 首先查找标题,然后仅在 Excel 工作表上加载某些列
- python - 如何在不使用collect()和for循环的情况下将一个(IP地址)的特定部分与RDD python pyspark中另一列中的其他IP地址进行比较
- typescript - TypeScript + RequireJs + 其他库 (pdfjs)
- r - 有没有办法计算数据框列中的观察次数并将其保存为字符串?
- mongodb - 如何更快地执行此 mongoDB 查找聚合?
- c# - 如何防止标签在 for 循环中相互重叠
- javascript - 如何将一个列表中的值存储到特定属性的另一个列表中?
- scss-mixins - SCSS mixin 第二个参数未正确编译
- c - 在STM32上调用Timer_callback时丢失指针地址
- r - 如何在R中的几个步骤中收集列而不丢失分组