问题
I'm new to d3 and reactjs. I was trying to make a bar chart with following Rect.js componenet
I've tried to debug right before // enter-update but with no avail.
import React, { Component } from 'react'
import * as d3 from 'd3';
const dataset = [14, 68, 24500, 430, 19, 1000, 5555];
const width = 600;
const height = 400;
export default class Rect extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
}
componentDidMount() {
this.renderRect();
}
componentDidUpdate() {
this.renderRect();
}
renderRect() {
this.container = d3.select(this.refs.container);
// draw refs rectangle
this.rects = this.container.selectAll("bar")
.data(dataset)
.enter();
// exit
this.rects.exit().remove();
// enter-update
this.rects = this.rects.enter()
.append("rect")
.merge(this.rects)
.attr("y", d => 24500 - d)
}
render() {
return (
<svg ref="container" width={width} height={height}>
</svg>
)
}
}
The error message is TypeError: this.setAttribute is not a function; When I debug, I found the error only appears when I have attr chained after merge(this.rects) but I don't understand why.
回答1:
Here is a minimal example of the issue:
var rect = container.selectAll("rect")
.data([1,2,3])
.enter(); // return a selection of entered placeholders
var merge = rect.enter() // return a selection of entered placeholders
.append("rect") // return a selection of appended nodes
.merge(rect) // merge appended nodes with entered placeholders.
.attr("someAttribute",0); // set an attribute for both appended nodes and entered placeholders.
The issue is straightforward: the merged selection isn't what you think it is.
The selection rect is a selection of placeholder nodes created by .enter() - not actual nodes in the DOM. They have a few methods, but no method for setting attributes. This is why the above code, or your code, will produce the error: this.setAttribute is not a function, as setAttribute is not a method of an entered placeholder (see the source here).
Instead we just drop the first .enter() statement. Which will also lead to the behavior you want, as we probably don't want rect to be an enter selection, since we do exit and update after. Instead we want rect to be a selection of existing rect elements, not placeholders. Modifying the above we get to account for this change we get:
var rect = container.selectAll("rect")
.data([1,2,3])
rect.enter().append("rect").merge(rect)...
rect.exit()....
Or with your code:
// draw refs rectangle
this.rects = this.container.selectAll("bar")
.data(dataset)
// No enter here
// exit
this.rects.exit().remove();
// enter-update
this.rects = this.rects.enter()
.append("rect")
.merge(this.rects)
.attr("y", d => 24500 - d)
来源:https://stackoverflow.com/questions/57315527/typeerror-this-setattribute-is-not-a-function