25

I'm trying to 'reset' a ReactJS element.

In this case, the element is 90%+ of the contents of the page.

I'm using replaceState to replace the state of the element with with its initial state.

Unfortunately, sub-elements which have their own 'state' do not reset. In particular, form fields keep their contents.

Is there a way of forcing a re-render of an element, which will also cause sub-elements to re-render, as if the page had just loaded?

fadedbee
  • 37,386
  • 39
  • 142
  • 236
  • You should probably pass the state as props to the children – David Hellsing Oct 14 '14 at 13:03
  • If you use the [controlled components](https://facebook.github.io/react/docs/forms.html#controlled-components) paradigm mentioned in the React docs and store the state high up the hierarchy where you are calling `replaceState`, you can "reset" the state of the form as well. – Ross Allen Oct 14 '14 at 21:36
  • 1
    @ssorallen The inputs are embedded in elements which have their own functionality and communications with the server. e.g. a "username" field which does it's own AJAX checking for duplicates, as part of *field* validation. – fadedbee Oct 15 '14 at 19:49
  • I strongly suggest you read through the React team's [Flux architecture](https://facebook.github.io/flux/docs/overview.html). Giving each component control of data is going to make it feel like you're fighting React, as is the case here. Push state as high up the component hierarchy as possible and use callbacks from descendants to trigger data changes up in the hierarchy. – Ross Allen Oct 16 '14 at 00:31

5 Answers5

52

Adding a key to the element forces the element (and all its children) to be re-rendered when that key changes.

(I set the value of 'key' to simply the timestamp of when the initial data was sent.)

render: function() {
  return (
    <div key={this.state.timestamp} className="Commissioning">
      ...
fadedbee
  • 37,386
  • 39
  • 142
  • 236
7

The this.replaceState(this.getInitialState()) method doesn't actually reset children that are inputs, if that's what you're looking for. For anyone looking to just reset their form fields, there is a standard DOM reset() function that will clear all the inputs in a given element.

So with React, it'd be something like this:

this.refs.someForm.getDOMNode().reset();

Doumentation:

https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset

Chris Dolphin
  • 1,342
  • 15
  • 26
4

If it is a form you want to reset, you simply can use this

// assuming you've given {ref: 'form'} to your form element
React.findDOMNode(this.refs.form).reset();
nonkertompf
  • 377
  • 1
  • 2
  • 12
1

While I don't personally think you should store local, interim component state (like in-progress input boxes) in a centralized location (like a flux store) in most cases, here it may make sense, depending on how many you have, especially since it sounds like the inputs already have some server interaction/validation around them. Pushing that state up the component hierarchy or into some other central location may help a lot in this case.

One alternative idea off the top of my head is to use a mixin in components that might need to reset local state, and do some kind of event triggering, etc. to make it happen. For example, you could use Node's EventEmitter or a library like EventEmitter3 with a mixin like this (warning: not tested, maybe best this as pseudocode :)

var myEmitter = new EventEmitter(); // or whatever

var ResetStateMixin = {
  componentWillMount: function() {
    myEmitter.on("reset", this._resetState);
  },

  componentWillUnmount: function() {
    myEmitter.off("reset", this._resetState);
  },

  _resetState: function() {
    this.replaceState(this.getInitialState());
  },

  triggerReset: function() {
    myEmitter.emit("reset");
  }
};

Then you could use it in components like so:

React.createClass({
  mixins: [ResetStateMixin],

  getInitialState: function() {
    return { ... };
  },

  onResetEverything: function() {
    // Call this to reset every "resettable" component
    this.triggerReset();
  }
});

This is very basic and pretty heavy handed (you can only reset all components, every component calls replaceState(this.getInitialState()), etc.) but those problems could be solved by extending the mixin a bit (e.g. having multiple event emitters, allowing component-specific resetState implementations, and so forth).

It's worth noting that you do have to use controlled inputs for this to work; while you won't need to push your state all the way up the component hierarchy, you'll still want all your inputs to have value and onChange (etc.) handlers.

Michelle Tilley
  • 149,782
  • 38
  • 355
  • 303
  • In what circumstances is this better than adding a `key` to the element? – fadedbee Oct 16 '14 at 13:39
  • @brandon, may I ask you to have a look at a 'react render' related question here : http://stackoverflow.com/questions/27913004/react-js-render-a-component-from-outside-react ? – Istiaque Ahmed Jan 13 '15 at 13:09
  • I agree with you on the flux solution. Just weighs on my mind the potential of firing an action every time the form changes (there's an input change). – backdesk Apr 22 '16 at 10:07
0

You could also use

document.forms[0].reset()