React遍历State存储列表传Props后内容不显示问题求助
问题:React组件遍历State列表传递Props后,仅渲染测试文本,视频及内容不显示
尝试遍历React组件State中的列表,将每个列表项作为Props传递给Video组件,期望渲染对应视频、标题和描述,但仅显示Video组件里的测试<h1>test</h1>,视频及相关内容未显示。
原代码
YoutubeFetch组件
export class YoutubeFetch extends Component { constructor(props) { super(props) this.state = { playlist: [], title: [], description: [], thumbnails: [], }; } componentDidMount() { return fetch(url) .then((response) => response.json()) .then((responseJson) => { // console.log('responseJson', responseJson) const playlist = responseJson.items.map(obj => "https://www.youtube.com/embed/" + obj.snippet.resourceId.videoId); this.setState({ playlist }); const description = responseJson.items.map(obj => obj.snippet.description); this.setState({ description }); const thumbnails = responseJson.items.map(obj => obj.snippet.thumbnails.default.url); this.setState({ thumbnails }); const title = responseJson.items.map(obj => obj.snippet.title); this.setState({ title }); }) .catch((error) => { console.log(error) }) } render() { return ( <Container> <Row> {this.state.playlist.map((index) => <Video key={index} video={this.state.playlist[index]} title={this.state.title[index]} description={this.state.description[index]} /> )} </Row> </Container> ) } }
Video组件
function Video(props) { return ( <Container> <Row> <h1>test</h1> <ReactPlayer controls url={props.video} // height="75%" playing={false} width="100%" /> </Row> <Row> <h1>{props.title}</h1> <p>{props.description}</p> </Row> </Container> ) } export default Video
问题分析
核心错误出在YoutubeFetch组件的render方法中:
this.state.playlist.map((index) => ...)这里的index实际是playlist数组的元素值(即视频链接字符串),而非数组索引。- 后续用
this.state.playlist[index]、this.state.title[index]取值时,因为index是字符串,会返回undefined,导致Video组件的props.video、props.title、props.description均为undefined,所以视频和文本内容无法渲染。
另外,componentDidMount中多次调用setState会触发多次组件渲染,建议合并为一次以提升性能。
修正方案
修正后的YoutubeFetch组件
export class YoutubeFetch extends Component { constructor(props) { super(props) this.state = { playlist: [], title: [], description: [], thumbnails: [], }; } componentDidMount() { return fetch(url) .then((response) => response.json()) .then((responseJson) => { // 一次性提取所有数据并更新state,避免多次渲染 const playlist = responseJson.items.map(obj => "https://www.youtube.com/embed/" + obj.snippet.resourceId.videoId); const description = responseJson.items.map(obj => obj.snippet.description); const thumbnails = responseJson.items.map(obj => obj.snippet.thumbnails.default.url); const title = responseJson.items.map(obj => obj.snippet.title); this.setState({ playlist, description, thumbnails, title }); }) .catch((error) => { console.log(error) }) } render() { return ( <Container> <Row> {this.state.playlist.map((videoUrl, index) => <Video key={index} video={videoUrl} title={this.state.title[index]} description={this.state.description[index]} /> )} </Row> </Container> ) } }
关键修改点
- 调整
map函数参数为(videoUrl, index):第一个参数是当前视频链接(数组元素),第二个是数组索引 - 直接传递
video={videoUrl},title和description通过index对应取值 - 合并
setState调用,一次性更新所有State字段,减少不必要的渲染
进阶优化(可选)
可以将数据整理为对象数组,避免多数组同步的潜在问题:
// componentDidMount中修改 const videos = responseJson.items.map(obj => ({ url: "https://www.youtube.com/embed/" + obj.snippet.resourceId.videoId, title: obj.snippet.title, description: obj.snippet.description, thumbnail: obj.snippet.thumbnails.default.url })); this.setState({ videos }); // render中修改 {this.state.videos.map((video, index) => <Video key={index} video={video.url} title={video.title} description={video.description} /> )}
内容的提问来源于stack exchange,提问作者Jellychews
相关产品推荐
相关产品推荐

