我正在尝试使用C3在我的React项目中渲染图表。
我所做的是动态生成一个id(UUID)并将其附加到我的图表组件中的div
。然后,我在componentDidMount
中呈现组件后调用一些代码。这是一种常见的模式,我在其他项目中看到过。
起初,一切似乎都很好。但是,在反复刷新页面后,有时图表生成不起作用。我得到的错误是:
DOMException: Failed to execute 'querySelector' on 'Document': '#a-really-long-id' is not a valid selector.
我尝试使用setTimeout
延迟图表附加,但奇怪的是我仍然得到相同的结果,即使在10秒延迟后。这让我相信这不是竞争条件,而是由其他因素造成的。也许C3读取DOM一次并且不响应变化?但这无法解释为什么它有时会起作用......
即使尝试从Chrome开发者控制台中按ID选择元素也无效。
这是我的完整组件代码:
// assets/js/index.jsx
import React from 'react';
import uuid from 'uuid/v4';
import c3 from 'c3';
class Chart extends React.Component {
constructor(props) {
super(props);
this.id = uuid();
this._update = this._update.bind(this);
}
_update() {
const data = this.props.data;
this.chart = c3.generate({
bindto: `#${this.id}`,
data: {
columns: [
['Male', 0],
['Female', 0],
['Brand', 0]
],
type: 'bar',
colors: {
Male: '#0066CC',
Female: '#FF6666',
Brand: '#808080'
},
groups: [
['Male', 'Female', 'Brand']
],
order: null
},
bar: {
width: {
ratio: 0.3
}
},
transition: {
duration: 500
},
tooltip: {
show: false
},
axis: {
x: { show: false },
y: { show: false },
},
size: { width: 220, height: 320 },
grid: {
x: { show: false }
},
legend: {
show: false
}
});
setTimeout(function() {
this.chart.load({
columns: [
['Male', data.male],
['Female', data.female],
['Brand', data.brand]
]
});
}, 500);
}
componentDidMount() {
this._update();
}
render() {
return (
<div id={this.id} className="chart"></div>
);
}
}
export default Chart;
这可以作为评论添加,但由于它很大,添加它作为答案。
你使用的是html4 / html5语义吗?
根据HTML4(https://www.w3.org/TR/html401/types.html)
ID和NAME令牌必须以字母([A-Za-z])开头,后面可以跟任意数量的字母,数字([0-9]),连字符(“ - ”),下划线(“_”) ,冒号(“:”)和句号(“。”)。
根据HTML5(https://www.w3.org/TR/html5/dom.html)
在HTML元素上指定时,id属性值在元素树的所有ID中必须是唯一的,并且必须至少包含一个字符。该值不得包含任何空格字符。
您的uuid有时可能会生成有效的ID,有时可能不生成(不确定uuid是如何工作的)
如果您不使用HTML5语义,则只需添加<!DOCTYPE html>
即可
在你的HTML文档的顶部,并尝试。
也,
您在逻辑中使用了settimeout,并且在您使用this.Chart时使用了settimeout
this
,现在将引用settimeout而不是类。
你能尝试改变吗?
setTimeout(function() {
this.chart.load({
columns: [
['Male', data.male],
['Female', data.female],
['Brand', data.brand]
]
});
}, 500);
至
setTimeout( () => {
this.chart.load({
columns: [
['Male', data.male],
['Female', data.female],
['Brand', data.brand]
]
});
}, 500);