React中使用Chart.js 2展示图表时出现内存泄漏错误
React图表组件首次加载内存泄漏/渲染失败问题
我用React + Chart.js实现了一个展示潜在客户(Leads)数量的柱状图组件,代码如下:
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from "chart.js" import { Bar } from "react-chartjs-2" ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend) function Reports() { const [graph, setGraph] = useState({}) const options = { responsive: true, plugins: { legend: { position: "top", }, title: { display: true, text: "Chart.js Bar Chart", }, }, } const handleAllLeadsGenerated = () => { axios({ method: "get", url: `${serverUrl}/reports/leads`, headers: { Authorization: `Bearer ${token}`, }, }) .then((res) => { console.log("response: ", res) setGraph({ labels: res.data.map((row) => { return row.firstname }), datasets: [ { label: "Leads Generation", data: res.data.map((row, index) => { return parseInt(row.countn) }), backgroundColor: "rgba(255, 99, 132, 0.5)", }, ], }) }) .catch((err) => { console.log("error: ", err) }) } useEffect(() => { handleAllLeadsGenerated() // eslint-disable-next-line }, []) return ( <> <div className="content"> <ToastContainer position="top-right" autoClose={5000} hideProgressBar={false} newestOnTop closeOnClick rtl={false} pauseOnFocusLoss draggable pauseOnHover theme="colored" /> <Tabs> <TabList> <Tab>Leads Generation</Tab> <Tab>Recuiters Report</Tab> </TabList> <TabPanel> <Row> <Col md="12"> <Card> <CardHeader style={{ display: "flex", alignItems: "center" }}> <CardTitle tag="h4">Leads Info</CardTitle> <Button onClick={handleAllLeadsGenerated}>Reload</Button> </CardHeader> <CardBody>{graph ? <Bar options={options} data={graph} /> : <Spinner animation="border" />}</CardBody> </Card> </Col> </Row> </TabPanel> </Tabs> </div> </> ) } export default Reports
问题现象
- 首次加载页面、刷新页面或从其他页面进入该组件时,出现内存泄漏错误,页面空白无内容渲染
- 临时缓解方式:注释掉
CardBody中的<Bar />组件,编译后再取消注释,图表能正常显示,但上述场景下仍会报错
解决方案
1. 修复初始状态判断逻辑
当前graph初始值为{},而空对象在JS中属于真值,导致graph ? ... : ...的判断永远为真——首次渲染时<Bar />拿到的是没有labels和datasets的空数据,直接触发Chart.js的渲染错误。
把初始状态改为null:
const [graph, setGraph] = useState(null)
2. 取消请求防止内存泄漏
组件卸载时如果请求还未完成,会导致内存泄漏。用axios的CancelToken取消未完成的请求:
useEffect(() => { const source = axios.CancelToken.source(); const handleAllLeadsGenerated = () => { axios({ method: "get", url: `${serverUrl}/reports/leads`, headers: { Authorization: `Bearer ${token}`, }, cancelToken: source.token }) .then((res) => { setGraph({ labels: res.data.map(row => row.firstname), datasets: [{ label: "Leads Generation", data: res.data.map(row => parseInt(row.countn)), backgroundColor: "rgba(255, 99, 132, 0.5)", }] }) }) .catch((err) => { if (!axios.isCancel(err)) { console.log("error: ", err) } }) } handleAllLeadsGenerated(); return () => { source.cancel("组件卸载,取消请求"); }; }, [token, serverUrl])
3. 补全依赖项
移除eslint-disable-next-line注释,将token和serverUrl加入useEffect的依赖数组,避免闭包导致的 stale 数据问题。
4. 可选:添加数据合法性校验
在设置图表数据前,校验接口返回的res.data是否为有效数组,避免空数据导致的渲染异常:
.then((res) => { if (Array.isArray(res.data) && res.data.length > 0) { setGraph({ labels: res.data.map(row => row.firstname), datasets: [{ label: "Leads Generation", data: res.data.map(row => parseInt(row.countn)), backgroundColor: "rgba(255, 99, 132, 0.5)", }] }) } else { // 处理空数据场景,比如展示空图表或提示 setGraph({ labels: [], datasets: [{ label: "Leads Generation", data: [] }] }) } })
内容的提问来源于stack exchange,提问作者PakDragoon
相关产品推荐
相关产品推荐

