在Express应用的React组件中使用D3生成图形失败如何解决
问题根因
你使用的express-react-views是服务端静态渲染工具,仅会将React组件转换为纯HTML字符串返回给浏览器,不会打包任何客户端侧的JavaScript代码到页面中。你编写的useEffect逻辑仅存在于服务端的组件源码里,根本没有被发送到浏览器环境,因此不会在页面加载后执行,D3的绘制逻辑自然不会触发。
可行解决方案
方案1:轻量场景直接嵌入客户端脚本
如果不需要复杂的React交互逻辑,最简单的方案是直接把D3绘制逻辑作为客户端脚本嵌入模板,无需依赖React钩子执行:
// views/d3_show_nolib.js import React from "react"; export default function App() { return ( <div> <p>D3 Example</p> <svg id="d3-svg" width="100" height="100"></svg> <script src="https://d3js.org/d3.v7.min.js"></script> <script> {` const svg = d3.select('#d3-svg'); svg .append("circle") .attr("r", 15) .attr("fill", "red") .attr("stroke", 1.5) .attr('cx', 10) .attr('cy', 10); `} </script> </div> ); }
该方案无需额外打包工具配置,修改后即可直接运行。
方案2:保留React逻辑,补充客户端水合
如果需要使用React的完整交互能力,你需要额外配置客户端JS打包和水合逻辑:
- 在
app.js中配置静态资源目录,用于存放打包后的客户端JS:
// app.js 新增配置 app.use(express.static(path.join(__dirname, 'public')));
- 修改组件代码,添加宽高属性和客户端水合逻辑:
// views/d3_show_nolib.js import React, { useEffect, useRef } from "react"; import { select } from "d3"; import { hydrateRoot } from 'react-dom/client'; export default function App() { const svgRef = useRef(); useEffect(() => { const svg = select(svgRef.current); svg .append("circle") .attr("r", 15) .attr("fill", "red") .attr("stroke", 1.5) .attr("cx", 10) .attr("cy", 10); }, []); return ( <div id="root"> <p>D3 Example</p> <svg ref={svgRef} width="100" height="100"></svg> <script src="/js/bundle.js"></script> </div> ); } // 仅在客户端环境执行水合 if (typeof window !== 'undefined') { hydrateRoot(document.getElementById('root'), <App />); }
- 使用esbuild、webpack等打包工具,将该组件、React、ReactDOM、D3等依赖打包为
public/js/bundle.js即可。
额外注意
你原本的代码没有给svg设置宽高,也没有给圆形设置cx、cy坐标,即使逻辑正常执行也可能看不到完整的圆形,上述示例中已经补充了相关属性。
内容的提问来源于stack exchange,提问作者Gabriele
相关产品推荐
相关产品推荐

