I am revisiting the code from this issue but now on a more recent version of semiotic (^1.7.13), d3-scale (^2.0.0) and react (^16.2.0). When I run the code as is, I get the following react error:
"Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." The console adds:
"The above error occurred in the component:
in XYFrame (at TimeSelector.js:135)"
This is before any interaction has taken place. The page renders for a split second and then errors out.
If I comment out:
//xScaleType={scaleTime()}
the page renders, but the brush does not work as expected: the handles stay where they are and the ticks get updated very fast (as compared to the brush movement).
I have commented out the setState calls in brushDuring and brushEnd, but that did not change the behavior.
For completeness sake, here is my component:
import React from "react";
import { XYFrame } from "semiotic";
import { scaleTime } from "d3-scale";
var data;
export default class TimeSelector extends React.Component {
constructor(props) {
super(props);
data = [
{
px:this.props.start,py:1
},
{
px:this.props.stop,py:1
}
];
this.state = {
start:data[0].px,
stop:data[1].px,
data:data,
align:true
}
this.brushDuring = this.brushDuring.bind(this);
this.brushEnd = this.brushEnd.bind(this);
}
brushDuring(e) {
if(e!==null && e!==undefined){
this.setState({start:e[0], stop:e[1]});
}
}
brushEnd(e) {
if(e!==null && e!==undefined){
this.setState({start:e[0], stop:e[1]});
}
}
render() {
return (
<div>
<div>
<XYFrame
className='-ts'
// leave some room (60 pixels) for the controls
size={[this.props.width, this.props.height-30]}
lines={[{coordinates:this.state.data}]}
xAccessor="px"
yAccessor="py"
//xScaleType={scaleTime()}
yExtent={[0,2]}
xExtent={[this.state.start, this.state.stop]}
lineStyle={d => ({
stroke: "grey",
strokeWidth: "10px",
opacity: 0.4,
})}
axes={[
{
orient: "bottom",
ticks: 10
}
]}
margin={{ left: 60, top: 55, bottom: 40, right: 40 }}
interaction={{
during: this.brushDuring,
end: this.brushEnd,
brush: "xBrush",
extent: [this.state.start,this.state.stop],
}}
/>
</div>
</div>
);
}
};
I can see that the brush example still works, which puzzles me.
Update: If I remove the callbacks from the interaction, then the behaviour is as expected, but the events do not fire, of course.
interaction={{
//during: this.brushDuring,
//end: this.brushEnd,
brush: "xBrush",
extent: [this.state.start,this.state.stop],
}}
Update 2: If I comment out the following lines:
In the constructor:
// this.brushDuring = this.brushDuring.bind(this);
// this.brushEnd = this.brushEnd.bind(this);
In the render function:
//xScaleType={scaleTime()}
And redefine my event callbacks as arrow functions:
brushDuring = (e) => {
if(e!==null && e!==undefined){
this.setState({start:e[0], stop:e[1]});
}
}
brushEnd = (e) => {
if(e!==null && e!==undefined){
this.setState({start:e[0], stop:e[1]});
}
}
everything seems to work just fine.