Reputation: 884
I am writing a game and when the game is over, I want it to reset to the initial state. I haven't found any meaningful information in the docs for this, so I've been playing around with adding a reset method to my Game class. First, I attempted doing the follow in hopes of creating a base class I could extend later, but using a variable for the component name fails:
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
...
};
}
reset() {
var node = ReactDOM.findDOMNode(this),
ComponentName = this.constructor.name;
if (node) {
ReactDOM.unmountComponentAtNode(node);
ReactDOM.render(<ComponentName />, node);
}
}
...
}
I moved on, and tried to hardcode the component name as follows:
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
...
};
}
reset() {
var node = ReactDOM.findDOMNode(this);
if (node) {
ReactDOM.unmountComponentAtNode(node);
ReactDOM.render(<Game />, node);
}
}
...
}
This works really well, but I am wondering if there is a built-in way that is better, or a more generic way.
Upvotes: 7
Views: 12730
Reputation: 11369
Update Please disregard the previous answer, replaceState is obviously not available in the ES2015 class pattern. Anyway, another solution is to keep an instance of the game in a wrapper component's state.
Working fiddle: https://jsfiddle.net/dannyjolie/upktozt1/1/
This will just remove the old game from App's state when you reset to a new game, and a new game will take its place.
class App extends React.Component {
constructor(props) {
super(props);
this.newGame = this.newGame.bind(this);
this.state = {
game: ()=><Game />
};
}
newGame () {
this.setState({
game: () => <Game />
});
}
render () {
const ActiveGame = this.state.game;
return (
<div>
<ActiveGame />
<button onClick={this.newGame}>RESET GAME</button>
</div>
);
}
}
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
foo: 'Bar'
};
this.onButtonClick = this.onButtonClick.bind(this);
}
onButtonClick () {
this.setState({
somethingElse: 'Hello',
foo: 'Changed foo'
});
}
render () {
return (
<div>
<button onClick={this.onButtonClick}>Set state.somethingElse</button>
<p>state.foo: {this.state.foo}</p>
<p>state.somethingElse: {this.state.somethingElse || '(not defined yet)'}</p>
</div>
);
}
}
Upvotes: 6
Reputation: 136
I've just applied another solution to this problem using setState and iterating over the state's own properties, setting them to undefined
, which is working nicely for me:
class Example extends React.Component
{
constructor(props){
super(props);
this._handleInputChange = this._handleInputChange.bind(this);
this._submitHandler = this._submitHandler.bind(this);
this._resetHandler = this._resetHandler.bind(this);
this._setInitialState = this._setInitialState.bind(this);
this.state = this._setInitialState();
}
_resetHandler(){
this.setState((prevState, props) => {
var newState = {};
for( var key in prevState ) {
if ( prevState.hasOwnProperty(key) ) {
newState[key] = undefined;
}
}
if( typeof this._setInitialState === 'function' ){
Object.assign(newState, this._setInitialState());
}
return newState;
});
}
_setInitialState(){
return {
mode: 'advanced',
created: {},
changed: {}
};
}
_handleInputChange(){
// do stuff to change the state
}
}
where _setInitialState returns whatever properties need to be initialized for the app to work.
This combines the advantages of not needing to maintain a full outline of your state in an initializer object, while also not requiring the overhead of re-mounting the component on reset.
Upvotes: 0
Reputation: 1288
If you need only reset state
then you can move default state into some function or variable and when you need reset state only call setState
with value from this function or variable.
Example:
class Game extends React.Component {
constructor(props) {
super(props);
this.state = this.getState(); // set state from getState result
this.onButtonClick = this.onButtonClick.bind(this);
this.onReset = this.onReset.bind(this);
}
getState() {
return {
number: 0
}
}
onReset() {
this.setState(this.getState()) // set state from getState result
}
onButtonClick () {
this.setState({
number: this.state.number + 1
});
}
render () {
return (
<div>
<button onClick={this.onButtonClick}>
Increment
</button>
<p>{this.state.number}</p>
<button onClick={this.onReset}>
Reset
</button>
</div>
);
}
}
Upvotes: 2