Author avatar

Gaurav Singhal

How to Trigger a Form Submit in Child Component with Redux

Gaurav Singhal

  • Nov 25, 2019
  • 10 Min read
  • 13,927 Views
  • Nov 25, 2019
  • 10 Min read
  • 13,927 Views
Web Development
React

Introduction

In this guide, we will learn how to trigger a form submission by dispatching an action from a component outside the form. There are often situations where different child forms are related to each other but fall into different components. In this guide, we will discuss how to consolidate data from different child components and submit them.

Building the Form Component

two fields: email and password. On input change of these fields, we will dispatch an action to update the form values in the global store object.

Let's first get the primary form component right.

1class SignInForm extends Component {
2  constructor(props) {
3    super(props);
4    this.state = {
5      values: {
6        email: "",
7        password: ""
8      }
9    };
10  }
11
12  submitForm = e => {
13    e.preventDefault();
14    // dispatch FORM_SUBMIT action
15  };
16
17  handleInputChange = e =>
18    this.setState(
19      {
20        values: { ...this.state.values, [e.target.name]: e.target.value }
21      },
22      () => {
23        // dispatch SET_FORM_VALUES action
24      }
25    );
26
27  render() {
28    return (
29      <div>
30        <form onSubmit={this.submitForm}>
31          <div className="input-group">
32            <label htmlFor="email">E-mail Address</label>
33            <input
34              type="email"
35              name="email"
36              id="email"
37              value={this.state.values.email}
38              onChange={this.handleInputChange}
39              title="Email"
40              required
41            />
42          </div>
43          <div className="input-group">
44            <label htmlFor="password">Password</label>
45            <input
46              type="password"
47              name="password"
48              id="password"
49              value={this.state.values.password}
50              onChange={this.handleInputChange}
51              title="password"
52              required
53            />
54          </div>
55          <button type="submit">Sign In</button>
56        </form>
57      </div>
58    );
59  }
60}
61
62export default SignInForm;
jsx

As you can see in the above code, we are keeping the form values in the component state. However, for the form values to be accessible outside the form component, the values should be in the global store. Therefore, in the handleInputChange() handler, we are going to dispatch an action with the form values in the payload.

Now, let's connect the <SignInForm /> component with Redux.

1import { connect } from "react-redux";
2
3class SignInForm extends Component {
4  submitForm = e => {
5    e.preventDefault();
6    this.props.dispatch({
7      type: "SUBMIT_FORM"
8    });
9  };
10
11  handleInputChange = e =>
12    this.setState(
13      {
14        values: { ...this.state.values, [e.target.name]: e.target.value }
15      },
16      () =>
17        this.props.dispatch({
18          type: "SET_FORMVALUES",
19          payload: this.state.values
20        })
21    );
22
23  render() {
24    return (
25      //
26    );
27  }
28}
29
30export default connect(null)(SignInForm);
jsx

Notice above in the handleInputChange() method that we are dispatching the action with the form values in the payload attribute.

The Reducer

Our reducer will be as follows (it's just a simple function that will return the state based on the action type):

reducer.js

1const initialState = {
2  formValues: {},
3  message: ""
4};
5
6const reducer = (state = initialState, action) => {
7  switch (action.type) {
8    case "SET_FORMVALUES":
9      return {
10        ...state,
11        formValues: action.payload
12      };
13    case "SUBMIT_FORM":
14      console.log("--- Triggered Form submission ---");
15      console.log("Form Data - ", state.formValues);
16      return {
17        ...state,
18        message: "Form submitted!!"
19      };
20    default:
21      return state;
22  }
23};
24
25export default reducer;
js

For SUBMIT_FORM action, we will display the values in the console. In a real application, though, you'd probably make an HTTP request to an external server to post the data or authenticate the user.

Wrapping Root with <Provider />

index.js

1import { Provider } from "react-redux";
2import { createStore } from "redux";
3
4import SignInForm from "./SignInForm";
5
6import reducer from "./reducer";
7
8const store = createStore(reducer);
9
10function App() {
11  return (
12    <Provider store={store}>
13      <div className="App">
14        <h1>Sign In To Your Account</h1>
15        <SignInForm />
16      </div>
17    </Provider>
18  );
19}
jsx

At this point, if you run this example and submit the form, you should be able to see the form values in the console .

console

Triggering Form Submission from Another Component

Now that the form submission has been successfully triggered by the <SignInForm /> component, let's try and trigger the form submission from a separate component.

For that, let's create a simple <Button /> component and dispatch the SUBMIT_FORM action in the button click handler.

Buttton.js

1import { connect } from "react-redux";
2
3const Button = props => (
4  <div>
5    Click this to
6    <button onClick={e => props.dispatch({ type: "SUBMIT_FORM" })}>
7      Trigger Form submit
8    </button>
9    from outside the form
10  </div>
11);
12
13export default connect(null)(Button);
jsx

In the index.js file, we will import this component and place it just after the <SignInForm /> component.

index.js

1// ...
2import Button from "./Button";
3
4function App() {
5  return (
6    <Provider store={store}>
7      <div className="App">
8        <h1>Sign In To Your Account</h1>
9        <SignInForm />
10        <Button />
11      </div>
12    </Provider>
13  );
14}
jsx

Now run the application again, but this time click on the second button. You should see the Triggered Form Submission message in the console, same as before.

Complete Source Code

index.js

1import React from "react";
2import ReactDOM from "react-dom";
3import { Provider } from "react-redux";
4import { createStore } from "redux";
5
6import "./styles.css";
7
8import SignInForm from "./SignInForm";
9import Button from "./Button";
10
11import reducer from "./reducer";
12
13const store = createStore(reducer);
14
15function App() {
16  return (
17    <Provider store={store}>
18      <div className="App">
19        <h1>Sign In To Your Account</h1>
20        <SignInForm />
21        <Button />
22      </div>
23    </Provider>
24  );
25}
26
27const rootElement = document.getElementById("root");
28ReactDOM.render(<App />, rootElement);
jsx

reducer.js

1const initialState = {
2  formValues: {},
3  message: ""
4};
5
6const reducer = (state = initialState, action) => {
7  switch (action.type) {
8    case "SET_FORMVALUES":
9      return {
10        ...state,
11        formValues: action.payload
12      };
13    case "SUBMIT_FORM":
14      console.log("--- Triggered Form submission ---");
15      console.log("Form Data - ", state.formValues);
16      return {
17        ...state,
18        message: "Form submitted!!"
19      };
20    default:
21      return state;
22  }
23};
24
25export default reducer;
js

SignInForm.js

1import React, { Component } from "react";
2import { connect } from "react-redux";
3
4class SignInForm extends Component {
5  constructor(props) {
6    super(props);
7    this.state = {
8      values: {
9        email: "",
10        password: ""
11      }
12    };
13  }
14
15  submitForm = e => {
16    e.preventDefault();
17    this.props.dispatch({
18      type: "SUBMIT_FORM"
19    });
20  };
21
22  handleInputChange = e =>
23    this.setState(
24      {
25        values: { ...this.state.values, [e.target.name]: e.target.value }
26      },
27      () =>
28        this.props.dispatch({
29          type: "SET_FORMVALUES",
30          payload: this.state.values
31        })
32    );
33
34  render() {
35    return (
36      <div>
37        <form onSubmit={this.submitForm}>
38          <div className="input-group">
39            <label htmlFor="email">E-mail Address</label>
40            <input
41              type="email"
42              name="email"
43              id="email"
44              value={this.state.values.email}
45              onChange={this.handleInputChange}
46              title="Email"
47              required
48            />
49          </div>
50          <div className="input-group">
51            <label htmlFor="password">Password</label>
52            <input
53              type="password"
54              name="password"
55              id="password"
56              value={this.state.values.password}
57              onChange={this.handleInputChange}
58              title="password"
59              required
60            />
61          </div>
62          <button type="submit">Sign In</button>
63        </form>
64        <div className="message">
65          {this.props.message.length > 0 && this.props.message}
66        </div>
67      </div>
68    );
69  }
70}
71
72const mapStateToProps = state => ({
73  message: state.message
74});
75
76export default connect(mapStateToProps)(SignInForm);
jsx

Button.js

1import React from "react";
2import { connect } from "react-redux";
3
4const Button = props => (
5  <div>
6    Click this to
7    <button onClick={e => props.dispatch({ type: "SUBMIT_FORM" })}>
8      Trigger Form submit
9    </button>
10    from outside the form
11  </div>
12);
13
14export default connect(null)(Button);
jsx

styles.css

1.App {
2  font-family: sans-serif;
3}
4
5.input-group {
6  margin-bottom: 10px;
7}
8
9.input-group label {
10  display: block;
11  margin-bottom: 5px;
12}
13
14button {
15  border: none;
16  padding: 8px 24px;
17}
18
19.message {
20  margin-top: 20px;
21  font-weight: 600;
22}
23
24.message.error {
25  color: red;
26}
css

Conclusion

In this guide, we learned how to dispatch actions from other components and submit form values stored in the global store. Many libraries, such as redux-form, work based on similar principles. I hope you're getting better at the Redux game every day. Until next time, keep hustling.