React项目中Axios的Promise then用法是否正确?如何控制渲染时机?
React Axios 请求与渲染控制问题解答
嘿,我来帮你拆解下这个问题~
首先先回答你最关心的:你的then用法本身语法上是正确的,但代码里有几个可以优化的点,而且你提到的“状态被设置两次”其实是个误解,咱们一步步说:
为什么会看到两次状态相关的渲染?
你实际遇到的是两次组件渲染,而不是两次设置状态:
- 组件挂载时,
componentWillMount调用getUsers,此时axios请求还在进行中,组件会先以初始空数组的databaseUsers状态渲染一次; - 当axios请求完成,
then回调里执行setState,触发组件重新渲染,这时候databaseUsers才有真实数据。
这是React处理异步请求的正常流程,并不是then触发了两次状态设置哦。
代码里的小问题与优化点
- 弃用的生命周期:
componentWillMount已经从React v16.3开始被标记为不安全的生命周期,推荐改用componentDidMount来发起数据请求——它在组件挂载后只执行一次,更可靠,也避免了服务器端渲染时的重复调用问题。 - 无用的变量赋值:你把
axios.get()的结果赋值给users,但这个变量其实是一个Promise对象,不是获取到的用户数据,完全可以删掉这个赋值。
如何获得渲染控制权:等待数据返回再渲染?
想要让用户只看到加载完成后的内容,最常用的方案是添加加载状态(loading),或者在父组件提前获取数据再传递。下面给你两种具体实现:
方案1:组件内部管理加载状态(最常用)
给state新增isLoading字段,初始为true,请求完成后设为false,render时根据这个状态决定显示加载提示还是实际内容:
class Participants extends React.Component{ constructor(props){ super(props); this.state = { databaseUsers: [], isLoading: true // 新增加载状态 } this.getUsers = this.getUsers.bind(this); } // 用async/await改造,让异步代码更易读 async getUsers(){ try { const response = await axios.get('/users/get-users'); this.setState({ databaseUsers: response.data, isLoading: false // 请求完成,关闭加载状态 }); } catch (error) { console.error('获取用户数据失败:', error); this.setState({ isLoading: false }); // 出错也要关闭加载,避免卡死 } } // 替换为componentDidMount componentDidMount(){ this.getUsers(); } render(){ const { isLoading, databaseUsers } = this.state; // 加载中时显示提示 if (isLoading) { return <div>加载用户数据中...</div>; } // 数据就绪后渲染实际内容 console.log(databaseUsers); return ( <div> {databaseUsers.map(user => ( <div key={user.id}>{user.name}</div> ))} </div> ); } }
方案2:父组件提前获取数据(实现单次渲染)
如果希望Participants组件挂载时就有数据,完全不需要初始空渲染,可以把请求逻辑放到父组件里,等数据就绪后再渲染Participants:
// 父组件 class UserList extends React.Component { state = { users: [], isLoading: true }; async componentDidMount() { try { const response = await axios.get('/users/get-users'); this.setState({ users: response.data, isLoading: false }); } catch (error) { console.error('获取数据失败:', error); this.setState({ isLoading: false }); } } render() { if (this.state.isLoading) { return <div>加载中...</div>; } // 数据就绪后才渲染Participants组件 return <Participants databaseUsers={this.state.users} />; } } // Participants组件(简化) class Participants extends React.Component{ render(){ console.log(this.props.databaseUsers); return ( <div> {this.props.databaseUsers.map(user => ( <div key={user.id}>{user.name}</div> ))} </div> ); } }
这样Participants组件只会在数据准备好后被挂载,自然只会渲染一次。
总结
- 你的
then用法没问题,但用async/await能让异步逻辑更清晰; - 两次渲染是React的正常流程,通过loading状态可以让用户无感知;
- 想要彻底避免初始空渲染,就把请求逻辑上移到父组件,提前准备好数据再传递。
内容的提问来源于stack exchange,提问作者Justplayit
相关产品推荐
相关产品推荐

