When & Where do you clear State in ReactJs?
<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>