
React 组件的生命周期决定了 componentDidMount 总是在首次渲染之后执行,因此无法真正“在渲染前加载数据”;正确做法是首次渲染时展示加载态,待异步数据就绪后触发重渲染并显示完整内容。
react 组件的生命周期决定了 `componentdidmount` 总是在首次渲染之后执行,因此无法真正“在渲染前加载数据”;正确做法是首次渲染时展示加载态,待异步数据就绪后触发重渲染并显示完整内容。
在 React 中,组件挂载(mount)必然先于 componentDidMount 执行,而首次 render() 也必然发生在挂载完成之后——这是框架底层设计决定的,不可绕过。因此,所谓“让数据在渲染前加载”,本质上是一个误解;真实可行的目标是:避免空白或报错渲染,提供良好的加载体验,并确保图表仅在数据就绪后才初始化。
上述代码中存在几个关键问题需修正:
-
全局变量污染:
var rows = []声明在组件外部,导致多个实例共享同一数组,极易引发状态混乱; -
未处理加载状态:
render()直接使用空数组this.state.rows,导致Chart接收无效数据(如[columns, ...[]]),可能报错或显示空白; -
未触发状态更新:原代码中
rows.push(...)操作的是全局rows数组,未调用setState,因此组件不会重新渲染; - 缺少错误与加载反馈:用户无从知晓数据是否正在获取、是否失败。
✅ 正确解法是采用条件渲染 + 状态驱动:
- 初始
state.rows = []; -
componentDidMount中发起请求,成功后通过this.setState({ rows })更新状态; -
render()中判断rows.length:若为空,显示加载提示(如<div>Loading...</div>);否则渲染Chart; - 使用
map替代for循环,提升可读性与函数式风格。
以下是优化后的完整实现:
重要:对 React 或 Next.js 代码的任何更改必须先阅读本技能。Vercel 工程团队的 React 与 Next.js 指南,涵盖可视化...
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';
const 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 {
state = {
rows: [],
isLoading: true,
error: null,
};
async componentDidMount() {
try {
const valori = await loadAttivita();
const rows = valori.map(({ Descrizione }) => [
'2014Spring',
Descrizione,
'autumn',
new Date(2014, 2, 22),
new Date(2014, 5, 20),
null,
100,
null,
]);
this.setState({ rows, isLoading: false });
} catch (err) {
console.error('Failed to load activities:', err);
this.setState({ isLoading: false, error: 'Caricamento dati fallito' });
}
}
render() {
const { rows, isLoading, error } = this.state;
if (isLoading) return <div style="{{" color: padding:>Caricamento diagramma in corso...</div>;
if (error) return <div style="{{" color: padding:>{error}</div>;
if (rows.length === 0) return <div style="{{" color: padding:>Nessuna attività disponibile</div>;
return (
<div>
<p style="{{" color: textalign: margin:>Diagramma Gantt</p>
<chart charttype="Gantt" width="100%" height="400px" data="{[columns," ...rows options="{options}"></chart>
</div>
);
}
}
const mapStateToProps = (state) => ({
isFetching: state.auth.isFetching,
isAuthenticated: state.auth.isAuthenticated,
errorMessage: state.auth.errorMessage,
});
export default withRouter(connect(mapStateToProps)(GaantView));
? 关键改进说明:
- ✅ 使用
isLoading和error状态明确区分加载、失败、空数据三种场景; - ✅
rows严格限定为组件内部state,杜绝全局变量副作用; - ✅ 错误捕获 + 用户友好提示,增强健壮性;
- ✅
height显式设置("400px"而非"100%"),避免Chart在父容器高度未定时代渲染异常; - ✅ 样式微调(如
textAlign替代已废弃的alignContent),符合现代 CSS 实践。
? 进阶建议:若需更高性能或服务端渲染(SSR)支持,可考虑使用 getServerSideProps(Next.js)或 React.Suspense + lazy 配合自定义 useData Hook 实现更优雅的数据预取模式。但对标准 CRA 或 Redux 应用,上述 componentDidMount + setState + 条件渲染 仍是清晰、可靠、符合 React 哲学的标准实践。










