React调用TMDB API获取数据后子组件接收值异常问题排查与解决
我刚看完你的问题,简直太有共鸣了!我之前用React做API数据传递的时候也踩过好几个一模一样的坑,来帮你拆解一下问题到底出在哪,以及为什么改成函数组件就解决了:
你碰到的核心问题
Props名称拼写错误(最致命的)
看你的父组件代码,传递给子组件的props是moviesRes:<MovieList moviesRes={this.state.movies}/>但不管是初始的类组件还是修改后的类组件,你在子组件里一直用的是
movieRes(少了一个s)!这直接导致子组件根本拿不到父组件传递的数据,自然显示undefined或者长度为0。TMDB API返回结构没处理对
TMDB的discover/movie接口返回的JSON结构是包含results数组的对象(简化版如下):{ "page": 2, "results": [/* 电影数据数组 */], "total_pages": 100 }你在父组件里直接把整个返回对象存到state的
movies里:this.setState({ movies: data });但子组件需要的是
data.results这个数组,直接对整个对象用map肯定会出问题——因为对象没有map方法。类组件的state同步问题
你的初始子组件在constructor里把props存到了自己的state里:this.state = { movies: this.props.movieRes }但React类组件的
constructor只会执行一次,当父组件fetch完成更新state后,子组件的state不会自动同步最新的props,除非你手动在componentDidUpdate里处理,这也是修改类组件代码后仍无效的原因之一。
为什么改成函数组件就解决了?
函数组件和类组件的核心区别之一是:函数组件每次渲染都会拿到最新的props,不需要手动处理state同步的问题。而且你在最终的函数组件里:
- 修正了props名称(推测你同步修改了父组件的props传递名称)
- 直接使用props而非存到state里,避免了同步问题
- 加了
if(!movies)的判断,优雅处理了数据未加载完成的状态
补充:如果想继续用类组件解决,需要做这些修改
- 修正props名称,保持父子组件一致
父组件:
子组件类组件:<MovieList movies={this.state.movies}/>import React, { Component } from 'react'; export default class MovieList extends Component{ render(){ // 解构props并设置默认空数组,避免报错 const { movies = [] } = this.props; if(movies.length === 0){ return <h1>Loading...</h1> } return( <ul> {movies.map((movie, index)=>{ return <li key={index}>{movie.title}</li>; })} </ul> ); } } - 父组件正确处理API返回数据
fetch(req).then(response =>{ return response.json(); }).then(data =>{ console.log(data); // 存储results数组而非整个响应对象 this.setState({ movies: data.results }); }).catch(err => { console.log("ERROR: " + err); }) - 替换过时的生命周期钩子
把componentWillMount换成componentDidMount(前者已被React标记为过时API):componentDidMount(){ this.fetchMovie(); }
内容的提问来源于stack exchange,提问作者tufailra97
相关产品推荐
相关产品推荐

