简体   繁体   English

使用SVG Rect On Click处理程序更改React State

[英]Change React State with SVG Rect On Click handler

Generally I make sure to include a code example for my problem, however in this case my code is 100% similar to the following D3 Radio Button example , which I am simply trying to include in a react component of mine. 通常,我确保为自己的问题提供一个代码示例,但是在这种情况下,我的代码与下面的D3单选按钮示例 100%相似,我只是尝试将其包含在我的react组件中。

The relevant code from the example is the on-click handler: 该示例中的相关代码是单击处理程序:

.on("click",function(d,i) {
  updateButtonColors(d3.select(this), d3.select(this.parentNode))
  d3.select("#numberToggle").text(i+1)
});

however, rather than toggling a number, I am trying to change the state of my react app when this radio button is clicked. 但是,我没有切换数字,而是在单击此单选按钮时尝试更改我的应用程序的状态。 For now, let's say I'm simply trying to set the state to be one of 1, 2, or 3, that way (i + 1) is the state I'd like to set. 现在,假设我只是试图将状态设置为1、2或3之一,那样(i +1)就是我要设置的状态。

I tried calling setState() directly in the on click handler here, however my state didn't change. 我尝试在此处的点击处理程序中直接调用setState(),但是我的状态没有改变。 Any thoughts on how I can do this? 关于如何执行此操作的任何想法? Let me know if more of my code is needed here. 让我知道这里是否需要更多代码。

Edit: I've tried adding a snippet of what I have so far, but i'm struggling to get it to work here on stackoverflow. 编辑:我已经尝试添加到目前为止的代码片段,但是我正在努力使其在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> 

You seem to be mixing up the this scope inside the click handler, you both use the this for the selector as for the react component. 您似乎在单击处理程序中混用了this范围,您都将this用作选择器以及react组件。

Normally we could retain the this scope using arrow functions, but as you seem to need it for d3 aswell, just create a local variable that saves the current context, so you can reuse it in your click function 通常,我们可以使用箭头函数保留this作用域,但是对于d3来说似乎也需要它,只需创建一个保存当前上下文的局部变量,即可在单击函数中重用它

// 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});
})

Then your current code would be working (true it only shows the 3 buttons, and selects either of the 3) 然后您当前的代码将正常工作(正确的是,它仅显示3个按钮,并选择3个按钮之一)

Please note that in your sample code, the chartWidth and chartHeight variable were undefined, so I set them to 320x240 so it matches a bit with the rendering space here on SO 请注意,在您的示例代码中, chartWidthchartHeight变量未定义,因此我将它们设置为320x240,因此它与此处的渲染空间有点匹配

 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> 

A nitpick on the combination of , , best practice, you should try to do all DOM manipulations inside instead. 结合和最佳实践,您应该尝试在内部执行所有DOM操作。

Now for a chart that might not be completely possible, but those 3 buttons can easily be rendered without the need of 现在,对于一个可能并非完全不可能的图表,但无需即可轻松渲染这三个按钮

I haven't combined these rendering engines yet, so I cannot really say if there are downsides to your current approach 我还没有结合使用这些渲染引擎,所以我不能真正说出您当前方法的缺点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM