React中如何将接口查询结果存入state?代码错误排查
问题分析与修复方案
嘿,我一眼就看到你代码里的两个关键问题啦,这也是很多React新手容易踩的坑:
1. 异步请求的时机与顺序问题
你在constructor里同时调用了this.fetchData()和this.getCalcs(),但fetchData是异步操作(axios的post请求需要时间返回数据)。当getCalcs执行时,axios还没拿到接口数据,this.state.calcs还是初始的空数组,所以this.listItems会被设置成空的映射结果,之后就算接口返回数据更新了state,listItems也不会重新生成。
2. 实例属性无法触发组件重新渲染
你把listItems存在了实例的this.listItems里,而不是React的state或者在render方法里动态生成。React只有当state或props变化时才会重新执行render方法,实例属性的改变不会触发组件更新,所以就算之后this.state.calcs有数据了,页面也不会显示出来。
修复后的代码
我们可以做这几个调整:
- 把
fetchData的调用移到componentDidMount生命周期里(这是React官方推荐的发起异步请求的时机) - 去掉
this.listItems这个实例属性,直接在render方法里动态生成列表项,这样每次state更新时,render都会重新执行,生成最新的列表
import React, { Component } from "react"; import ReactDOM from "react-dom"; import axios from "axios"; export default class AllCalcs extends Component { constructor (props) { super(props); this.state = { calcs: [] }; } // 组件挂载完成后发起异步请求 componentDidMount() { this.fetchData(); } fetchData() { axios.post('/api/all-calcs') .then(response => this.setState({calcs: response.data})) .catch(error => console.log(error)); } render() { // 直接在render里生成列表项 const listItems = this.state.calcs.map((calc, index) => ( <a key={index} href="#" className="list-group-item list-group-item-action flex-column align-items-start"> <div className="d-flex w-100 justify-content-between"> <h5 className="mb-1">{calc.h1}</h5> <small>3 days ago</small> </div> <p className="mb-1">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p> <small>Donec id elit non mi porta.</small> </a> )); return ( <div> <div className="list-group"> {listItems} </div> </div> ); } } if (document.querySelector('#all-calcs')) { ReactDOM.render(<AllCalcs />, document.querySelector('#all-calcs')); }
额外优化建议
- 尽量不要用数组索引作为
key,如果你的calc对象有唯一的id属性,用calc.id作为key会更符合React的最佳实践,避免列表更新时出现不必要的重渲染问题。 - 可以在state里加一个
loading状态,在请求完成前显示加载提示,提升用户体验。
内容的提问来源于stack exchange,提问作者user11709406
相关产品推荐
相关产品推荐

