javascript - 尝试使用 d3.select() 选择 React DOM ref 并遇到错误
问题描述
我正在尝试在 d3 中构建一个折线图,当新数据传递到 React 组件时它会更新。我useEffect()
用来选择一个<path>
DOM 元素,然后使用 D3 代码来操作它。但是,我收到一个错误:
无法读取 null 的 ownerDocument。
这是回购: https ://github.com/inspectordanno/baby_names
这是中的代码./src/components/LineChart.js
:
import React, { useEffect, useState, useRef } from 'react';
import * as d3 from 'd3';
const LineChart = ({ name }) => {
const [nameData, setNameData] = useState();
const lineContainer = useRef();
const xAxisContainer = useRef();
const yAxisContainer = useRef();
const margin = {top: 20, right: 10, bottom: 20, left: 10};
const width = 800 - margin.left - margin.right;
const height = 600 - margin.top - margin.bottom;
useEffect(() => {
//I could just import the file locally, but I want to simulate an api call
const getNameData = async () => {
const url = `https://raw.githubusercontent.com/inspectordanno/baby_names/master/parse_json/names/${name}.json`;
const resolvedNameData = await d3.json(url);
//sets local state to resolved data
setNameData(resolvedNameData);
}
getNameData();
}, [name])
useEffect(() => {
//d3 code goes in here
if (nameData && lineContainer.current && xAxisContainer.current && yAxisContainer.current) {
const years = nameData.map(d => d.year);
const proportions = nameData.map(d => d.prop);
const maleBirths = nameData.filter(birth => birth.sex === 'M');
const femaleBirths = nameData.filter(birth => birth.sex === 'F');
const xScale = d3.scaleLinear() //can do a time scale but making this simple
.domain(d3.extent(years)) //calculates min and max
.range([0, width]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(proportions)])
.range([height, 0]);
const xAxis = d3.axisBottom()
.scale(xScale);
const yAxis = d3.axisRight()
.scale(yScale);
const lineGenerator = d3.line()
.x(d => xScale(d.year))
.y(d => yScale(d.prop));
//create / update the line
const line = d3.select(lineContainer.current)
.data(femaleBirths)
line
.transition()
.duration(300)
.attr('d', lineGenerator)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 2.5)
//create / update the x axis
d3.select(xAxisContainer.current)
.transition()
.duration(500)
.call(xAxis)
//create / update the y axis
d3.select(yAxisContainer.current)
.transition()
.duration(500)
.call(yAxis);
}
}, [nameData, xAxisContainer.current, yAxisContainer.current, lineContainer.current])
return (
<svg
width={width}
height={height}
>
<g ref={xAxisContainer} transform={`translate(${margin.left}, ${height - margin.bottom})`} />
<g ref={yAxisContainer} transform={`translate(${margin.left}, ${margin.top})`} />
<g transform={`translate(${margin.left}, ${margin.top})`}>
<path ref={lineContainer} />
</g>
</svg>
);
}
export default LineChart;
出于某种原因,当我尝试选择lineContainer.current
并对其执行 D3 更新模式时,D3 给了我一个错误。但是轴工作正常,我在它们上使用相同的模式。为什么会这样?
解决方案
推荐阅读
- api - Sonos API 订阅回调已停止
- java - hibernate.cfg.xml 在阴影 jar 中的根目录中的多个依赖项
- python - 如何向dask提交大量长时间运行的并行任务?
- python - SettingWithCopyWarning - 如何修复此警告?
- angular - Angular 材质扩展面板默认关闭,但带有 routerLinkActive 的面板除外
- javascript - 为什么我在 JS 中的计时器功能不会开始倒计时?
- odoo - 在树视图中禁用创建按钮,但在 odoo 中保留导入
- azure - 无法从 Visual Studio for Mac 发布 Azure 函数
- java - 线程“GameThread”javax.media.j3d.CapabilityNotSetException 中的异常:组:无法设置转换
- c++ - 如何使用boost asio stable timer expiry获取执行时间点