React中给Div添加子元素时useRef的current属性仍返回undefined问题求助
问题原因
- 你直接在组件渲染逻辑中调用
drawChart,此时组件还没完成DOM挂载,ref.current还没有指向实际的DOM节点,自然会返回undefined或null - 你同时维护了回调ref绑定的
refState和useRef生成的ref两套引用,没有必要,存在取值不一致的风险 - 没有做旧节点清理逻辑,后续如果数据更新重新绘制,会出现柱子重复堆叠的问题
修正方案
直接用useRef绑定DOM节点,把绘制逻辑放到useEffect中,确保DOM挂载完成后再执行绘制即可,修改后的完整代码如下:
import React from "react"; import { useRef, useEffect } from "react"; import "./ExpenseFilter.css"; const ExpenseFilter = (props) => { const values = [100, 100, 340, 320, 500, 50, 45, 385, 95, 120, 90, 20]; const chartRef = useRef(null); const drawChart = (data, padding) => { // 加非空判断,避免DOM未挂载时报错 if (!chartRef.current) return; const max = Math.max.apply(Math, data); const chart = chartRef.current; // 清空旧节点,避免重复绘制 chart.innerHTML = ''; const barwidth = (chart.offsetWidth - (values.length - 1) * padding - data.length * 10) / data.length; let left = 0; for (let i in data) { let newbar = document.createElement("div"); newbar.setAttribute("class", "bar"); newbar.style.width = barwidth + "px"; newbar.style.height = (data[i] / max) * 100 + "%"; newbar.style.left = left + "px"; chart.appendChild(newbar); left += barwidth + padding + 10; props.OnChangeDiv(newbar); } }; // DOM挂载完成后或数据变更时才执行绘制 useEffect(() => { drawChart(values, 15); }, [values]); return ( <div className="wrapper1"> <div className="select" tabIndex="1"> <input className="selectopt" name="test" type="radio" id="opt1" checked /> <label htmlFor="opt1" className="option"> 2019 </label> <input className="selectopt" name="test" type="radio" id="opt2" /> <label htmlFor="opt2" className="option"> 2020 </label> <input className="selectopt" name="test" type="radio" id="opt3" /> <label htmlFor="opt3" className="option"> 2021 </label> <input className="selectopt" name="test" type="radio" id="opt4" /> <label htmlFor="opt4" className="option"> 2022 </label> <input className="selectopt" name="test" type="radio" id="opt5" /> <label htmlFor="opt5" className="option"> 2023 </label> </div> {/* 直接把ref绑定到DOM节点 */} <div id="chart" ref={chartRef} ></div> </div> ); }; export default ExpenseFilter;
额外优化建议
如果不想手动操作DOM,也可以用React声明式的写法渲染柱子:把计算好的柱子样式存到数组里,直接在JSX中遍历生成对应div.bar元素即可,不需要手动操作appendChild,更符合React的开发规范。
内容的提问来源于stack exchange,提问作者Vidyadhar M
相关产品推荐
相关产品推荐

