如何确保函数在React组件render()执行前完成运行?
问题根源
你遇到undefined有两个核心原因:
- 生命周期执行顺序错了:
componentDidMount是组件第一次render()执行完成、DOM已经挂载到页面之后才会触发的钩子,根本不可能在第一次render之前跑完你写在里面的异步请求,第一次渲染时拿不到数据是必然结果。 - 数据存储方式不对:你把接口返回的
issueDoc直接挂在this.issues上,这种手动修改实例属性的操作不会触发组件重渲染,就算后续异步请求拿到了数据,视图也不会自动更新。
推荐解决方案(符合React设计规范)
不要试图阻塞render()执行等待异步请求,这种做法会导致页面卡死,体验极差,正确做法是加加载状态做条件渲染:
- 把渲染依赖的动态数据全部放到
state中管理,不要直接挂在组件实例上 - 初始状态增加
loading标记,默认值为true,同时给接口数据设置初始值 - 异步请求逻辑仍然放在
componentDidMount中,请求完成后调用setState更新数据、把loading设为false render()方法中先判断加载状态,加载过程中返回加载占位内容(加载提示、骨架屏都可以),等数据就绪后再渲染依赖issueDoc的业务内容
示例代码:
class IssueComponent extends React.Component { constructor(props) { super(props); this.state = { loading: true, issueDoc: null, // 其他你需要的状态 }; } componentDidMount() { this.getIssueButtonCollection(); } async getIssueButtonCollection() { try { // 保留你原有的业务逻辑,调用getIssueDoc拉取数据 const issueDoc = await getIssueDoc(); this.setState({ issueDoc, loading: false }); } catch (err) { // 这里加错误处理逻辑,比如展示错误提示 this.setState({ loading: false }); } } render() { // 加载中或者数据不存在时,返回占位内容 if (this.state.loading || !this.state.issueDoc) { return <div className="loading">内容加载中...</div>; } // 数据就绪后正常渲染,这里访问this.state.issueDoc不会出现undefined return ( <div className="issue-container"> {/* 你的业务渲染逻辑 */} </div> ); } }
可选方案:父组件预加载数据
如果你就是要求组件第一次render的时候必须拿到完整数据,可以把数据请求逻辑上移到父组件:父组件完成接口请求之前不渲染当前子组件,等数据拿到之后再通过props把数据传给子组件、挂载子组件,这样子组件第一次执行render()的时候就已经能拿到完整数据了。
示例逻辑:
// 父组件 class ParentPage extends React.Component { state = { issueDoc: null }; componentDidMount() { getIssueDoc().then(res => { this.setState({ issueDoc: res }); }); } render() { if (!this.state.issueDoc) { return <div>页面加载中...</div>; } // 数据就绪后才挂载子组件,子组件render时props里已经带了完整数据 return <IssueComponent issueDoc={this.state.issueDoc} />; } }
注意:不要尝试用同步请求或者其他方式阻塞render执行,JavaScript是单线程的,阻塞渲染会导致整个页面卡死,用户完全无法交互,是非常差的实践。
内容的提问来源于stack exchange,提问作者runnerpaul
相关产品推荐
相关产品推荐

