Change component state when a button is pressed

The following is the HTML.

<script src="https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-xtp1/t39.3284-6/12624079_897774290317920_1379776191_n.js"></script> <script src="https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-xfp1/t39.3284-6/12624052_751451571621845_431133942_n.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script> <div class="row" id="container"> <div class="controls"> <span class="" id="controls-size">Size : <button id="controls-size-small">SMALL</button> <button id="controls-size-med">MEDIUM</button> <button id="controls-size-large">LARGE</button> </span> </div> <div id="game-container"> </div> </div> 

Below is Javscript

 var SizeEnum = { SMALL: 1, MEDIUM: 2, LARGE: 3 }; var Board = React.createClass({ getInitialState: function() { return { size: SizeEnum.MEDIUM }; }, componentWillMount: function() { if (this.state.size == SizeEnum.SMALL) { this.style = { width: 600 + 'px', height: 320 + 'px', margin: 'auto', border: '2px solid red' } } else if (this.state.size == SizeEnum.MEDIUM) { this.style = { width: 700 + 'px', height: 500 + 'px', margin: 'auto', border: '2px solid red' } } else if (this.state.size == SizeEnum.LARGE) { this.style = { width: 900 + 'px', height: 720 + 'px', margin: 'auto', border: '2px solid red' } } }, render: function() { return ( < div style = { this.style } > < /div> ) } }); ReactDOM.render(<Board / > , document.getElementById("game-container")); 

And some CSS

 #game-container { position: relative; margin-top: 32px; border: 1px solid black; width: 100%; } 

I want the Board component to be resized to the appropriate size when I click the corresponding button.

I tried to do it like this

 var board = ReactDOM.render(<Board />, document.getElementById("game-container")); document.getElementById("controls-size-small").onclick = changeBoardSize; document.getElementById("controls-size-med").onclick = changeBoardSize; document.getElementById("controls-size-large").onclick = changeBoardSize; function changeBoardSize(event) { var etid = event.target.id; console.log(etid); if (etid == "controls-size-small") { // method 1 board.state.size = SizeEnum.SMALL; } else if (etid == "controls-size-med") { // method 2 board.state.size = SizeEnum.MEDIUM; ReactDOM.render(<Board />, document.getElementById("game-container")); } else if (etid == "controls-size-small") { // method 3 board.setState({size: SizeEnum.SMALL}); ReactDOM.render(<Board />, document.getElementById("game-container")); } } 

But that will not work.

+6
source share
4 answers

You cannot set the state of a React component like this. The component must be responsible for setting its own state.

Inside the Board component, configure event listeners in componentDidMount. A better solution would be to allow buttons to be part of the React app, but that is beyond the scope of this question. So let's say that the buttons are not part of the React application, and then do something like this:

 var Board = React.createClass({ ... ... componentDidMount: function(){ var that = this; document.getElementById("controls-size-small").addEventListener('click', that.changeBoardSize, false); document.getElementById("controls-size-med").addEventListener('click', that.changeBoardSize, false); document.getElementById("controls-size-large").addEventListener('click', that.changeBoardSize, false); } changeBoardSize: function(e){ /* get the element id and do the enum things here */ this.setState({ size: newSize }); } render: function(){ ... ... } }); 

Then simply move all the elements of the componentWillMount component to the render function.

Update

Fiddle: https://jsfiddle.net/dannyjolie/r525ux66/

+3
source

You are taking the wrong approach. The most difficult part of the reaction is "Thinking in the reaction." If you want everything to be correct, the idea of โ€‹โ€‹directly accessing the DOM, as you do with document.getElementById, is outside the table.

The easiest way to get started is to display your button inside the render function of your Board component. You can then place the click handler inside the Board component to set the state.

This should help you:

  handleClick: function (event) { this.setState({ size: SizeEnum.SMALL }); }, render: function() { return ( <div> <div style = { this.style}></div> <input type="button" onClick={this.handleClick} </div> ) } 

Once you get it, if you want to separate your button from your button, you need to take a look at using the Flux implementation to pass state from component to component.

+2
source

You cannot directly change the state of a React component. Use setState instead . When you call setState , React will re-render the compoment.

Add a new setSize function to your command:

  var Board = React.createClass({ getInitialState: function() { return { size: SizeEnum.MEDIUM }; }, setSize: function(size) { this._setStyle(size); this.setState({size: size}); }, _setStyle: fiunction(size) { if (size == SizeEnum.SMALL) { this.style = { width: 600 + 'px', height: 320 + 'px', margin: 'auto', border: '2px solid red' } } else if (size == SizeEnum.MEDIUM) { this.style = { width: 700 + 'px', height: 500 + 'px', margin: 'auto', border: '2px solid red' } } else if (this.state.size == SizeEnum.LARGE) { this.style = { width: 900 + 'px', height: 720 + 'px', margin: 'auto', border: '2px solid red' } } }, componentWillMount: function() { this._setStyle(this.state.size); }, // ................ render: function() { return ( <div style={this.style}></div>) } }); function changeBoardSize(event) { var etid = event.target.id; console.log(etid); if (etid == "controls-size-small") { board.setSize(SizeEnum.SMALL); } else if (etid == "controls-size-med") { board.setSize(SizeEnum.MEDIUM); } else if (etid == "controls-size-small") { board.setSize(SizeEnum.LARGE); } } 
+1
source

This is an anti-pattern, although this is the right way to achieve what you are looking for.

Since ReactDOM.render returns an instance of the component being processed, you can use it and update it.

  function changeBoardSize(event) { var etid = event.target.id; console.log(etid); if (etid == "controls-size-small") { board.setState({size: SizeEnum.SMALL}); } else if (etid == "controls-size-med") { board.setState({size: SizeEnum.MEDIUM}); } else if (etid == "controls-size-small") { board.setState({size: SizeEnum.LARGE}); } } 

The right way to do this is to make Board components on them and attach event handlers, for example:

 var Board = React.createClass({ getInitialState: function() { return { size: SizeEnum.MEDIUM }; }, render: function() { return ( <div> <a href="#" onClick={this.onSizeChangeClick.bind(this, SizeEnum.SMALL)}>Small</a> <a href="#" onClick={this.onSizeChangeClick.bind(this, SizeEnum.MEDIUM)}>Medium</a> <a href="#" onClick={this.onSizeChangeClick.bind(this, SizeEnum.LARGE)}>Large</a> </div> ) }, onSizeChangeClick: function(size, event){ event.preventDefault(); this.setState({ size: size }); } }) 
0
source

All Articles