React中Axios请求后setState无法读取响应对象问题排查
问题:React调用Google Places API时,第二个
then无法读取res.data? 我尝试调用Google Places API,通过监听输入框onChange事件获取用户输入并发送请求,期望获取地点数组后将组件的sights状态更新为该数组。但遇到了奇怪的问题:第一个then能正确打印结果数组,第二个then里却报错无法读取undefined的data属性。
我的组件代码:
import React, {Component} from 'react'; import axios from 'axios'; class Search extends Component { constructor(props) { super(props); this.state= { sights: 'cat', city:'' } } onInputChange(city) { this.setState({city}); this.handleSubmit(city); } handleSubmit(event) { axios.get( "https://maps.googleapis.com/maps/api/place/textsearch/json?query=attractions+in+" + this.state.city + "&key=AIzaSyC5d4W-ei6o_C3eCrnJl24nuaeuAemhoJQ", { mode: "no-cors", header: { "Access-Control-Allow-Orgin": "http://localhost:8080", "Content-Type": "application/json", "Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept" }, withCredentials: true, credentials: "same-origin" } ) .then((res) => console.log(res.data.results)) .then((res) => { this.setState({ sights: res.data.results }); }) .then(console.log('got here')) .catch(function(err) { console.log("err", err); }) } render(){ return ( <div> <h2>{this.state.city}</h2> <h4>{this.state.sights}</h4> <input value={this.state.city} onChange={(event)=> this.onInputChange(event.target.value)} /> </div> ) } } export default Search;
测试用的then片段:
.then((res) => console.log(res.data.results)) .then((res) => { this.setState({ sights: res.data.results }); }) .then(console.log('got here'))
控制台输出:
- 打印出包含20个对象的地点数组
- 报错:
err TypeError: Cannot read property 'data' of undefined at eval (Search.jsx:63) - 打印
got here
解决方案
嘿,这个问题我之前也踩过坑!核心原因是Promise链式调用的返回值规则,咱们一步步拆解解决:
1. 为什么第二个then里的res是undefined?
Promise链式调用中,每个then接收的参数,是前一个then函数的返回值。你第一个then里只执行了console.log,没有返回任何内容,默认返回undefined,所以第二个then拿到的res就是undefined,自然会报错。
2. 为什么第三个then的console.log会提前执行?
你写的.then(console.log('got here'))是直接执行了console.log,把它的返回值(undefined)传给了then。正确写法是传递一个函数,这样才会在Promise完成后执行:
.then(() => console.log('got here'))
3. 修复代码的两种方式
方式一:在第一个then里返回响应对象
让后续then能拿到完整的响应数据:
axios.get(/* ... 请求地址和配置 ... */) .then((res) => { console.log(res.data.results); return res; // 关键:把响应对象返回给下一个then }) .then((res) => { this.setState({ sights: res.data.results }); }) .then(() => console.log('got here')) // 改成箭头函数,避免提前执行 .catch(function(err) { console.log("err", err); })
方式二:把操作合并到同一个then里
如果这些操作不需要分步骤依赖,直接合并更简洁:
axios.get(/* ... 请求地址和配置 ... */) .then((res) => { console.log(res.data.results); this.setState({ sights: res.data.results }); console.log('got here'); }) .catch(function(err) { console.log("err", err); })
额外提示:跨域问题
你当前设置的mode: "no-cors"可能导致后续无法正常解析响应(no-cors模式下响应body不可读取),建议去掉这个配置,改用以下方式解决跨域:
- 在React项目的
package.json中配置代理:"proxy": "https://maps.googleapis.com" - 使用Google Places API官方JavaScript SDK(更推荐,已处理跨域问题)
内容的提问来源于stack exchange,提问作者user9814109
相关产品推荐
相关产品推荐

