title: When & Where do you clear State in ReactJs?
body: <p>I have this code</p>
  
  <pre><code>import React from 'react';
  
  import 'materialize-css/sass/materialize.scss';
  import 'materialize-css/js/materialize.js';
  import 'font-awesome/scss/font-awesome.scss';
  import '../styles/main.scss';
  
  export default class AddStorageModal extends React.Component {
      constructor() {
          super();
          this.state = { storageName: "", sharingKey: "" };
      }
      handleChange(event) {
          this.setState({ [event.target.name]: event.target.value });
      }
      validate() {
          if (this.state.storageName === "" &amp;&amp; this.state.sharingKey == "") {
              console.log("validation error");
              return false;
          }
          this.props.createNewStorage(this.state);
      }
      resetForm() {
          this.setState({ storageName: "", sharingKey: "" })
          $(function () {
              Materialize.updateTextFields();
          });
      }
      render() {
          if (this.props.storages.openAddStorageModal) {
              $('#add-new-storage-modal').openModal({ dismissible: false });
          }
          else {
              $('#add-new-storage-modal').closeModal();
              this.resetForm( );
          }
          return (
              &lt;div id="add-new-storage-modal" className="modal" &gt;
                  &lt;div className="modal-content"&gt;
                      &lt;h6&gt;Enter your new Storage (Freezer, Pantry, etc.) &lt;/h6&gt;
                      &lt;div className="row"&gt;
                          &lt;form&gt;
                              &lt;div className="input-field col s12 m12 l12 "&gt;
                                  &lt;input id="storage_name" type="text" value={this.state.storageName} name="storageName" onChange={ (event) =&gt; this.handleChange(event) } /&gt;
                                  &lt;label htmlFor="storage_name"&gt;Storage Name&lt;/label&gt;
                              &lt;/div&gt;
                              &lt;br /&gt;
                              &lt;h4 className="center"&gt;OR&lt;/h4&gt;
                              &lt;h6&gt;Enter in the sharing key you were given.&lt;/h6&gt;
                              &lt;div className="input-field col s12 m12 l12 "&gt;
                                  &lt;input id="sharing_key" type="text"  value={this.state.sharingKey} name="sharingKey" onChange={ (event) =&gt; this.handleChange(event) }  /&gt;
                                  &lt;label htmlFor="sharing_key"&gt;Sharking Key&lt;/label&gt;
                              &lt;/div&gt;
                          &lt;/form&gt;
                      &lt;/div&gt;
                  &lt;/div&gt;
                  &lt;div className="modal-footer"&gt;
                      &lt;a href="#!" className="waves-effect waves-green btn-flat left" onClick={() =&gt; this.validate() }&gt;Add&lt;/a&gt;
                      &lt;a href="#!" className="waves-effect waves-green btn-flat" onClick={() =&gt; this.props.loadAddStorageModal(false) }&gt;Cancel&lt;/a&gt;
                  &lt;/div&gt;
              &lt;/div&gt;
          )
      }
  }
  </code></pre>
  
  <p>My orignal plan was each time my modal dialog re-renders I reset the form values by calling my resetForm() method.</p>
  
  <p>This does not work as I get errors about "changing state" in the render what does now make sense to me as it will cause the component to re-render.</p>
  
  <p>But this leads to me to the questions where do I clear the state then? I am trying to follow the redux pattern.</p>
  
  <p>I could do the clearing in "Validate()" method when the add is clicked.</p>
  
  <p>However "createNewStorage" does an ajax call. I am unsure how I would handle the situation if the ajax call fails. As a user I would expect a error message to be displayed but the modal should still be open with my inputted values.</p>
  
  <p>Here is full code if needed.</p>
  
  <pre><code>import React from 'react';
  import {connect} from 'react-redux';
  import {bindActionCreators} from 'redux';
  import 'materialize-css/sass/materialize.scss';
  import NavigationContainer from './NavigationContainer';
  import StorageItemsContainer from './StorageItemsContainer'
  
  import AddStorageModal from './AddStorageModal.js'
  import {loadAddStorageModal, createNewStorage} from '../actions/StorageActions.js'
  import '../styles/main.scss';
  
  
  class App extends React.Component {
    render() {
      return (
        &lt;div&gt;
          &lt;NavigationContainer /&gt;
           &lt;div className="container"&gt;
            &lt;StorageItemsContainer /&gt;
           &lt;/div&gt;
          &lt;AddStorageModal {...this.props} /&gt;
        &lt;/div&gt;
      )
    }
  }
  
  function mapStateToProps(state) {
      return {
          storages: state.storages
      };
  }
  
  function matchDispatchToProps(dispatch){
      return bindActionCreators({loadAddStorageModal: loadAddStorageModal, createNewStorage: createNewStorage}, dispatch);
  }
  
  
  export default connect(mapStateToProps, matchDispatchToProps)(App);
  </code></pre>
  
  <p>Action</p>
  
  <pre><code>export function fetchStorage() {
    return function(dispatch) {
        var payload = [
          {
              id: 1,
              name: "Fridge2",
              selected: true
          },
          {
              id: 2,
              name: "Closet2",
              selected: false
          },
          {
              id: 3,
              name: "Car2",
              selected: false
          }
      ];
       dispatch({type: "Fetch_Storage", payload: payload});
    }
  }
  
  export function loadAddStorageModal(load) {
      return function(dispatch) {
           dispatch({type: "Load_Add_Storage_Modal", payload: load});
      }
  }
  
  export function createNewStorage(storage) {
      return function(dispatch) {
           dispatch({type: "New_Storage_Created", payload: storage});
      }
  }
  
  export function selectStorage(storageId)
  {
      return function(dispatch) {
           dispatch({type: "Select_Storage", payload: storageId});
      }
  }
  </code></pre>
  
  <p>Reducer</p>
  
  <pre><code>export default function reducer(state = {
      fetchedStorages: [],
      openAddStorageModal: false,
      selectedStorage: null
  }, action) {
      switch (action.type) {
          case "Fetch_Storage": {
              var selected;
              if(state.fetchedStorages != [])
              {
                  selected =  action.payload[0]
              }
              return {
                  fetchedStorages: action.payload,
                  selectedStorage: selected
              }
          }
          case "Load_Add_Storage_Modal": {
              return {  
                  openAddStorageModal: action.payload,
                  fetchedStorages: state.fetchedStorages,
                  selectedStorage: state.selectedStorage
              }
          }
          case "New_Storage_Created": {
              var lastStorage = state.fetchedStorages.slice(-1);  // just for now
              return {
                  openAddStorageModal: false,
                  fetchedStorages: state.fetchedStorages.concat({ id: lastStorage[0].id + 1,  name:  action.payload.storageName}),
                  selectedStorage: state.selectedStorage
              }
          }
          case "Select_Storage": {
              var existingStorages =  state.fetchedStorages;
              var selectedStorage = null;
              for (var i = 0; i &lt; existingStorages.length; i++) {
                   var storage = existingStorages[i];
                   if (action.payload == storage.id) {
                       storage.selected = true;
                       selectedStorage = storage;
                   }else{
                       storage.selected = false;
                   }
                   existingStorages[i] = storage;
              }
              return {
                  fetchedStorages: existingStorages,
                  selectedStorage: selectedStorage
              }
  
          }
      }
  
  
      return state;
  }
  </code></pre>