javascript - 使用 SVG Rect On Click 处理程序更改 React 状态
问题描述
通常,我确保为我的问题包含一个代码示例,但是在这种情况下,我的代码与以下 D3 单选按钮示例100% 相似,我只是试图将其包含在我的反应组件中。
示例中的相关代码是点击处理程序:
.on("click",function(d,i) {
updateButtonColors(d3.select(this), d3.select(this.parentNode))
d3.select("#numberToggle").text(i+1)
});
但是,当单击此单选按钮时,我试图更改我的反应应用程序的状态,而不是切换一个数字。现在,假设我只是想将状态设置为 1、2 或 3 之一,这样(i + 1)就是我想要设置的状态。
我尝试在这里的点击处理程序中直接调用 setState() ,但是我的状态没有改变。关于我如何做到这一点的任何想法?让我知道这里是否需要更多我的代码。
编辑:我已经尝试添加到目前为止的内容片段,但我正在努力让它在 stackoverflow 上工作。
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
chartType: 1
}
}
drawChartTypeButton() {
// colors for different button states
const defaultColor= "#7777BB"
const hoverColor= "#0000ff"
const pressedColor= "#000077"
const bWidth= 8; //button width
const bHeight= 5; //button height
const bSpace= 1; //space between buttons
const x0 = 5; //x offset
const y0 = 5; //y offset
const labels = [1, 2, 3];
const updateButtonColors = function(button, parent) {
parent.selectAll("rect")
.attr("fill",defaultColor)
button.select("rect")
.attr("fill",pressedColor)
}
// groups for each button (which will hold a rect and text)
const chartTypeButton = d3.select('g.allbuttons')
const buttonGroups= chartTypeButton.selectAll("g.button")
.data(labels)
.enter()
.append("g")
.attr("class", "button")
.style("cursor", "pointer")
.on("click", function(d,i) {
updateButtonColors(d3.select(this), d3.select(this.parentNode))
this.setState({chartType: 2})
})
.on("mouseover", function() {
if (d3.select(this).select("rect").attr("fill") != pressedColor) {
d3.select(this)
.select("rect")
.attr("fill",hoverColor);
}
})
.on("mouseout", function() {
if (d3.select(this).select("rect").attr("fill") != pressedColor) {
d3.select(this)
.select("rect")
.attr("fill",defaultColor);
}
})
buttonGroups.append("rect")
.attr("class","buttonRect")
.attr("width",bWidth)
.attr("height",bHeight)
.attr("x", function(d,i) {return x0+(bWidth+bSpace)*i;})
.attr("y",y0)
.attr("rx",1) //rx and ry give the buttons rounded corners
.attr("ry",1)
.attr("fill",defaultColor)
// adding text to each toggle button group, centered
// within the toggle button rect
buttonGroups.append("text")
.attr("class","buttonText")
.attr("font-family", "arial")
.attr("font-size", "0.1em")
.attr("x",function(d,i) {
return x0 + (bWidth+bSpace)*i + bWidth/2;
})
.attr("y",y0)
.attr("text-anchor","middle")
.attr("dominant-baseline","central")
.attr("fill","black")
.text(function(d) {return d;})
}
componentDidMount() {
const chart = d3.select('.chart')
.attr('width', 320)
.attr('height', 240)
.attr("viewBox", "0, 0, " + 50 + ", " + 50 + "")
this.drawChartTypeButton();
}
render() {
return(
<div className='container'>
<svg className='chart'>
<g className="allbuttons" />
</svg>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id='root'>
Damnit Work
</div>
解决方案
您似乎this
在点击处理程序内部混淆了范围,您都将 this 用于d3选择器和 react 组件。
通常我们可以使用箭头函数来保留this
范围,但是您似乎也需要它来用于 d3,只需创建一个保存当前上下文的局部变量,这样您就可以在 click 函数中重用它
// create a local reference to "this" in the drawCharTypeButton function
const self = this;
// use the local reference to update the componenents state
.on("click", function(d,i) {
updateButtonColors(d3.select(this), d3.select(this.parentNode));
self.setState({chartType: 2});
})
然后您当前的代码将正常工作(真的,它只显示 3 个按钮,并选择 3 个中的任何一个)
请注意,在您的示例代码中,chartWidth
andchartHeight
变量未定义,因此我将它们设置为 320x240,因此它与 SO 上的渲染空间有点匹配
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
chartType: 1
}
}
drawChartTypeButton() {
// colors for different button states
const defaultColor= "#7777BB"
const hoverColor= "#0000ff"
const pressedColor= "#000077"
const bWidth= 8; //button width
const bHeight= 6; //button height
const bSpace= 0.5; //space between buttons
const x0 = 5; //x offset
const y0 = 14; //y offset
const labels = [1, 2, 3];
const updateButtonColors = function(button, parent) {
parent.selectAll("rect")
.attr("fill",defaultColor)
button.select("rect")
.attr("fill",pressedColor)
}
// groups for each button (which will hold a rect and text)
const self = this;
const chartTypeButton = d3.select('g.allbuttons')
const buttonGroups= chartTypeButton.selectAll("g.button")
.data(labels)
.enter()
.append("g")
.attr("class", "button")
.style("cursor", "pointer")
.on("click", function(d,i) {
updateButtonColors(d3.select(this), d3.select(this.parentNode))
self.setState({chartType: 2})
})
.on("mouseover", function() {
if (d3.select(this).select("rect").attr("fill") != pressedColor) {
d3.select(this)
.select("rect")
.attr("fill",hoverColor);
}
})
.on("mouseout", function() {
if (d3.select(this).select("rect").attr("fill") != pressedColor) {
d3.select(this)
.select("rect")
.attr("fill",defaultColor);
}
})
buttonGroups.append("rect")
.attr("class","buttonRect")
.attr("width",bWidth)
.attr("height",bHeight)
.attr("x", function(d,i) {return x0+(bWidth+bSpace)*i;})
.attr("y",y0)
.attr("rx",5) //rx and ry give the buttons rounded corners
.attr("ry",5)
.attr("fill",defaultColor)
// adding text to each toggle button group, centered
// within the toggle button rect
buttonGroups.append("text")
.attr("class","buttonText")
.attr("font-family", "arial")
.attr("font-size", "0.1em")
.attr("x",function(d,i) {
return x0 + (bWidth+bSpace)*i + bWidth/2;
})
.attr("y",y0+bHeight/2)
.attr("text-anchor","middle")
.attr("dominant-baseline","central")
.attr("fill","white")
.text(function(d) {return d;})
}
componentDidMount() {
const chart = d3.select('.chart')
.attr('width', 160)
.attr('height', 120)
.attr("viewBox", "0, 0, " + 50 + ", " + 50 + "")
this.drawChartTypeButton();
}
render() {
return(
<div className='container'>
<svg className='chart'>
<g className="allbuttons" />
</svg>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id='root'>
Damnit Work
</div>
关于d3、react、最佳实践组合的挑剔,您应该尝试在react内部进行所有 DOM 操作。
现在对于一个可能不完全可能的图表,但是这 3 个按钮可以很容易地呈现而不需要d3
我还没有组合这些渲染引擎,所以我不能说你目前的方法是否有缺点
推荐阅读
- flutter - 如何在 Flutter 中创建全局列表?
- r - 在R中data.frame中的两个参数上标记唯一组合的行
- c++ - STD 设置在内存中
- azure-devops - 将 Azure devops 服务器之间的工作项同步到 Azure devops Cloud
- javascript - 我有一个包含图像和文档的对象数组,我想检查 mime_type 并选择要在标签中显示的第一个元素(React)
- apache-spark - 过滤后 PySpark 不再工作
- wpf - WPF telerik GridView 聚合不会更新,直到焦点离开网格视图字段
- rotation - Google Cloud Storage - 处理来自环境外部的旋转密钥
- performance - 带有大数据的 QAreaSeries 的 QChart 非常慢
- javascript - React Axios 发布请求在 4 分钟后超时