title: How to close the Modal Dialog when state changed in React-Redux?
body: <p>Basically, I want to change the UI state in the Component when the Global state has been changed in the Redux-Store.</p>
  
  <p>My scenario is as follow:</p>
  
  <ol>
  <li>Show the Modal Form when a user clicks a "Add Student" button</li>
  <li>Show "Saving..." when user clicks "Save" button</li>
  <li>If an error occurs, the dialog should stay open and show Error</li>
  <li>If insertion is ok, the dialog should be closed automatically</li>
  </ol>
  
  <p><a href="https://i.stack.imgur.com/hl7fH.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/hl7fH.png" alt="enter image description here"></a></p>
  
  <p>I have achieved the first 3 points, but I'm stuck at the 4th point and don't know how to implement the <code>Close</code> feature after the successful insertion.</p>
  
  <p>I would like to run the following example code whenever isSubmitting/error has been changed in the Redux-Store.  But, I don't know where to run it.  I tried to put it in the render() method, but it doesn't work and I couldn't open the dialog anymore.</p>
  
  <p><em>Code to Check and Close the Modal</em></p>
  
  <pre><code>if (isSubmitting === false &amp;&amp; error === null)
       this.setState({ add: false });
  </code></pre>
  
  <p>I don't want to lift that UI state (Eg. IsModalOpen - bool) into the Global Redux store.  I have already put the UI state 'isSubmitting' into Redux and I don't want to keep adding UI states into the Redux Store.</p>
  
  <p>Could you please suggest me how I can close the dialog after the successful insertion?</p>
  
  <p>I put the sample code on the CodeSandbox and it's <a href="https://codesandbox.io/s/4xlk549rm4" rel="nofollow noreferrer">here</a></p>
  
  <p><strong>Reducer</strong></p>
  
  <pre><code>const initialState = {
        isSubmitting: false,
        error: null,
        student: null
      };
  
  function rootReducer(state = initialState, action) {
    switch (action.type) {
      case "STUDENT_ADD_BEGIN": {
        return {
          ...state,
          isSubmitting: true
        };
      }
      case "STUDENT_ADD_SUCCESS": {
        return {
          ...state,
          student: action.payload,
          error: null,
          isSubmitting: false
        };
      }
      case "STUDENT_ADD_ERROR": {
        return {
          ...state,
          isSubmitting: false,
          error: action.error,
          student: null
        };
      }
      default:
        return state;
    }
  }
  
  export default rootReducer;
  </code></pre>
  
  <p><strong>Container/Page</strong></p>
  
  <pre><code>class addStudentPage extends Component {
    constructor(props) {
      super(props);
      this.state = {
        dataList: [],
        add: false,
        edit: false,
        dataItem: {}
      };
    }
  
    getInitialState() {
      return {
        id: "",
        name: "TTCG"
      };
    }
  
    componentDidMount() {
      this.setState({
        dataItem: this.getInitialState()
      });
    }
  
    toggleAdd = () =&gt; {
      this.setState(prevState =&gt; ({
        add: !prevState.add
      }));
    };
  
    showAddNew = () =&gt; {
      this.toggleAdd();
  
      this.setState({
        dataItem: this.getInitialState()
      });
    };
  
    updateItemState = event =&gt; {
      const field = event.target.name;
      const value = event.target.value;
      let item = this.state.dataItem;
  
      item[field] = value;
  
      return this.setState({ dataItem: item });
    };
  
    handleAddNew = () =&gt; {
      let item = this.state.dataItem;
      item["id"] = uuid.v4();
      console.info(item);
      this.props.addStudentAction(item);
    };
  
    render() {
      const { isSubmitting, error } = this.props;
  
      return (
        &lt;Container&gt;
          &lt;h1&gt;Students&lt;/h1&gt;
          &lt;Button onClick={this.showAddNew} color="link"&gt;
            Add New Student
          &lt;/Button&gt;
          {this.state.add &amp;&amp; (
            &lt;AddStudent
              toggle={this.toggleAdd}
              modal={this.state.add}
              item={this.state.dataItem}
              onChange={this.updateItemState}
              onAddNew={this.handleAddNew}
              isSubmitting={isSubmitting}
              error={error}
            /&gt;
          )}
          {this.props.student &amp;&amp; (
            &lt;h6&gt;You have added a new student named: {this.props.student.name}&lt;/h6&gt;
          )}
        &lt;/Container&gt;
      );
    }
  }
  
  const mapStateToProps = state =&gt; {
    return {
      isSubmitting: state.studentReducer.isSubmitting,
      error: state.studentReducer.error,
      student: state.studentReducer.student
    };
  };
  
  const mapDispatchToProps = {
    addStudentAction: item =&gt; addStudentAction(item)
  };
  </code></pre>
  
  <p><strong>Modal Form</strong></p>
  
  <pre><code>export default class StudentAdd extends Component {
    render() {
      const {
        modal,
        toggle,
        item,
        onChange,
        onAddNew,
        isSubmitting,
        error
      } = this.props;
  
      return (
        &lt;Modal isOpen={modal} toggle={toggle} centered&gt;
          &lt;ModalHeader toggle={toggle}&gt;Add New Student&lt;/ModalHeader&gt;
          &lt;ModalBody&gt;
            {error &amp;&amp; &lt;Alert color="danger"&gt;{error}&lt;/Alert&gt;}
            &lt;Form&gt;
              &lt;FormGroup&gt;
                &lt;Label for="Name"&gt;Name&lt;/Label&gt;
                &lt;Input
                  type="text"
                  name="name"
                  id="Name"
                  value={item.name}
                  onChange={onChange}
                /&gt;{" "}
                type 'error' to simulate error
              &lt;/FormGroup&gt;
            &lt;/Form&gt;
          &lt;/ModalBody&gt;
          &lt;ModalFooter&gt;
            &lt;Button color="primary" onClick={onAddNew} disabled={isSubmitting}&gt;
              {isSubmitting ? "Saving..." : "Save"}
            &lt;/Button&gt;{" "}
            &lt;Button color="secondary" onClick={toggle}&gt;
              Cancel
            &lt;/Button&gt;
          &lt;/ModalFooter&gt;
        &lt;/Modal&gt;
      );
    }
  }
  </code></pre>
  
  <p><strong>UPDATES</strong></p>
  
  <p>It can be achieved by using <code>componentDidUpdate</code> lifecycle method as below:  please be careful that you check the props and states correctly before deriving the state.</p>
  
  <pre><code>componentDidUpdate(prevProps) {
      const { isSubmitting, error } = this.props;
      if (isSubmitting !== prevProps.isSubmitting || error !== prevProps.error) {
        if (isSubmitting === false &amp;&amp; error === null)
          this.setState({ add: false });
      }
    }
  </code></pre>
  
  <p>Or you can use <code>getDerivedStateFromProps</code> lifecycle method to re-calculate the props.  But I found it difficult to use than <code>componentDidUpdate</code>.  </p>