React组件:如何将componentDidMount数据加载移至render前执行?
在React类组件render前完成数据加载的实现方案
你当前的组件在componentDidMount中加载数据,这个生命周期钩子是在组件首次渲染完成后执行的,所以数据会在render之后才获取。要在render前完成数据加载,可以参考以下几种方案:
方案一:构造函数中发起异步请求(推荐)
构造函数是组件初始化时第一个执行的方法,在render之前触发。虽然构造函数不能直接用async/await,但可以通过.then()或单独封装异步方法来处理数据请求,同时添加加载状态控制渲染内容:
修改后的完整代码示例:
import React from 'react'; import { withRouter } from 'react-router-dom'; import { connect } from 'react-redux'; import { Chart } from 'react-google-charts'; import { loadAttivita } from '../../services/attivita'; let columns = [ { type: 'string', label: 'Task ID' }, { type: 'string', label: 'Task Name' }, { type: 'string', label: 'Resource' }, { type: 'date', label: 'Start Date' }, { type: 'date', label: 'End Date' }, { type: 'number', label: 'Duration' }, { type: 'number', label: 'Percent Complete' }, { type: 'string', label: 'Dependencies' }, ]; export const options = { height: 400, gantt: { trackHeight: 30, }, }; class GaantView extends React.Component { constructor(props) { super(props); this.state = { rows: [], isLoading: true, // 新增加载状态 key: 0, }; // 初始化时触发数据加载 this.fetchData(); } // 封装异步数据加载方法 fetchData = async () => { try { const valori = await loadAttivita(); // 格式化数据并更新state const formattedRows = valori.map(item => [ '2014Spring', item.Descrizione, 'autumn', new Date(2014, 2, 22), new Date(2014, 5, 20), null, 100, null, ]); this.setState({ rows: formattedRows, isLoading: false, }); } catch (err) { console.error('数据加载失败:', err); this.setState({ isLoading: false }); } }; render() { const { isLoading, rows } = this.state; // 加载中显示提示,避免空图表 if (isLoading) { return <div style={{ color: 'white', textAlign: 'center' }}>加载中...</div>; } return ( <div> <p style={{ color: 'white', alignContent: 'center' }}>Diagramma Gaant</p> {' '} <Chart chartType="Gantt" width="100%" height="100%" data={[columns, ...rows]} options={options} /> </div> ); } } function mapStateToProps(state) { return { isFetching: state.auth.isFetching, isAuthenticated: state.auth.isAuthenticated, errorMessage: state.auth.errorMessage, }; } export default withRouter(connect(mapStateToProps)(GaantView));
说明:
- 修复了你原代码中未更新state的问题(原代码将数据push到全局变量,但render使用的是state中的rows,导致图表无法显示数据)
- 通过
isLoading状态控制渲染内容,避免首次render时显示空图表
方案二:将数据请求移到父组件
如果希望子组件render时直接拥有数据,可以把加载逻辑放到父组件,父组件加载完成后再渲染GaantView:
父组件示例
import React from 'react'; import GaantView from './GaantView'; import { loadAttivita } from '../../services/attivita'; class ParentComponent extends React.Component { state = { attivitaData: null, isLoading: true, }; async componentDidMount() { const valori = await loadAttivita(); this.setState({ attivitaData: valori, isLoading: false, }); } render() { const { isLoading, attivitaData } = this.state; if (isLoading) { return <div style={{ color: 'white', textAlign: 'center' }}>加载中...</div>; } return <GaantView attivitaData={attivitaData} />; } }
修改后的GaantView组件
class GaantView extends React.Component { constructor(props) { super(props); this.state = { rows: this.formatData(props.attivitaData), key: 0, }; } // 格式化数据方法 formatData = (data) => { return data.map(item => [ '2014Spring', item.Descrizione, 'autumn', new Date(2014, 2, 22), new Date(2014, 5, 20), null, 100, null, ]); }; // 监听props变化,重新格式化数据 componentDidUpdate(prevProps) { if (prevProps.attivitaData !== this.props.attivitaData) { this.setState({ rows: this.formatData(this.props.attivitaData), }); } } render() { return ( <div> <p style={{ color: 'white', alignContent: 'center' }}>Diagramma Gaant</p> {' '} <Chart chartType="Gantt" width="100%" height="100%" data={[columns, ...this.state.rows]} options={options} /> </div> ); } }
说明:这种方式符合组件职责分离原则,子组件只负责渲染,数据请求逻辑交给父组件处理。
不推荐的方案:使用UNSAFE_componentWillMount
React已将componentWillMount标记为不安全生命周期(重命名为UNSAFE_componentWillMount),它可能在服务端渲染中被多次调用,且无法可靠处理异步错误,官方强烈不推荐使用,但如果一定要在render前执行,可以参考:
async UNSAFE_componentWillMount() { const valori = await loadAttivita(); const formattedRows = valori.map(item => [ '2014Spring', item.Descrizione, 'autumn', new Date(2014, 2, 22), new Date(2014, 5, 20), null, 100, null, ]); this.setState({ rows: formattedRows }); }
内容的提问来源于stack exchange,提问作者riki
相关产品推荐
相关产品推荐

