React的Piano组件useEffect初始渲染不运行 仅窗口resize时触发
问题根因
- 初始渲染阶段DOM未完成挂载,直接在组件顶层执行
const svgEl = d3.select(svgRef.current)时,svgRef.current为null,提前保存的svgEl是空选择集,初始执行useEffect时无法操作DOM完成渲染。 - 后续新增的空依赖useEffect依然使用了顶层提前声明的空
svgEl,因此无法生效。窗口调整时组件重新渲染,此时svgRef已经绑定了DOM元素,重新赋值的svgEl有效,渲染逻辑才会正常执行。
修复方案
将SVG元素的获取逻辑移到useEffect内部,保证每次执行渲染逻辑时都能拿到有效的DOM引用,修正后的代码如下:
const svgRef = React.useRef(null); const { width } = useWindowDimensions(); const height = width / 4; const keyData = generateKeyData(88, width); React.useEffect(() => { const svgEl = d3.select(svgRef.current); // 增加边界判断,避免初始宽度无效时报错 if (svgEl.empty()) return; svgEl.selectAll("*").remove(); generatePianoNode(svgEl, keyData); }, [keyData]); return ( <svg ref={ svgRef } width={ width } height={ height } /> );
改动说明
- 移除了组件顶层的
svgEl声明,改在useEffect内部动态获取,确保DOM已挂载、ref存在有效值 - 移除了依赖项中不稳定的
svgEl变量,仅保留keyData作为依赖即可:svgRef是React创建的稳定引用,不需要加入依赖列表 - 增加非空判断,兼容
useWindowDimensions初始返回无效宽度的边界场景
内容的提问来源于stack exchange,提问作者Batın Evirgen
相关产品推荐
相关产品推荐

