In this guide, we are going to look at how we can avoid using jQuery and use native JavaScript code to submit a form to React. Let's start by understanding why it's a bad idea to include jQuery with React.
Well, when you come into the React ecosystem, you don't need jQuery anymore. I'm not saying that they won't work together, they definitely will. But when you are using jQuery in React, you must be very careful and more thoughtful about the DOM updates and the state of the application.
Both jQuery and React serve the same purpose of manipulating the DOM. jQuery does that by direct DOM scripting and React by using the Virtual DOM. Modifying the DOM outside of the React Application means that React is possibly no longer handling state, events moreover UI rendering. Additionally, it also means that you are building one application with two different approaches, along with sending extra dependencies to the browser, which is inevitably going to increase the application size.
There's nothing in jQuery that native JavaScript cannot handle on its own because, in actuality, jQuery uses Vanilla Javascript. There are particular use cases when you want to use jQuery, like, for example, a jQuery plugin for creating sortable lists. But, even in that case, there probably is a React component available out there in the open-source community for doing the same.
For this demo, we will create a sign-in form with two fields: email and password.
We will keep our form state as follows:
1this.state = {
2 values: {
3 email: "",
4 password: ""
5 },
6 isSubmitting: false,
7 isError: false
8};
isSubmitting will be set to true when the form submission is triggered, and isError will be set to true when there is an error during the submission.
1<form onSubmit={this.submitForm}>
2 <div className="input-group">
3 <label htmlFor="email">E-mail Address</label>
4 <input
5 type="email"
6 name="email"
7 id="email"
8 value={this.state.values.email}
9 onChange={this.handleInputChange}
10 title="Email"
11 required
12 />
13 </div>
14 <div className="input-group">
15 <label htmlFor="password">Password</label>
16 <input
17 type="password"
18 name="password"
19 id="password"
20 value={this.state.values.password}
21 onChange={this.handleInputChange}
22 title="password"
23 required
24 />
25 </div>
26 <button type="submit">Sign In</button>
27</form>
1handleInputChange = e =>
2 this.setState({
3 values: { ...this.state.values, [e.target.name]: e.target.value }
4 });
5
6submitForm = e => {
7 e.preventDefault();
8 console.log(this.state.values);
9}
In the submitForm()
function, we will be submitting the form to a login API endpoint. I hacked up a dummy API, using node and express for this demo.
In the handleInputChange()
function, I have used the spread operator ...
. For those of you who are not familiar with it, it's the modern way (ES6 syntax) of expanding an iterable and spreading its element.
Earlier, if we had to make an API request, we would use the XML HTTP Request (XHR). I understand why most of you guys preferred jQuery AJAX over XHR; it had cleaner syntax compared to XHR which was horrific and messy.
But now JavaScript has a new native, Promise-based method to make network requests- the Fetch API.
"The Fetch API provides a JavaScript interface for accessing and manipulating parts of the HTTP pipeline, such as requests and responses. It also provides a global fetch() method that provides an easy, logical way to fetch resources asynchronously across the network." - MDN web docs
The Fetch API differs from jQuery.ajax() in two main ways:
The Promise returned by fetch() won't reject on HTTP error status, even if the response is an HTTP 404 or 500. Instead, it will typically resolve (with ok status set to false), and it will only reject on a network failure or if anything stopped the request from completing.
init
option must set.1fetch(url, { ...options })
2 .then(response => {
3 // Handle the response and return the data
4 })
5 .then(data => {
6 // Handle the data that is returned from the server
7 })
8 .catch(err => {
9 // Handle the error, if any
10 })
fetch()
optionally accepts a second "options" parameter which can include the method of the request (GET, POST, etc.), the body of the request, and, also, the headers. By default, the method of request is GET.
1fetch(`https://jsonplaceholder.typicode.com/posts`)
2 .then(res => res.json())
3 .then(data => console.log(data))
The json()
method resolves the response data to JSON object. Alternatively, we can also use text()
and blob()
methods.
1fetch(`https://jsonplaceholder.typicode.com/posts`, {
2 method: 'POST',
3 body: JSON.stringify(values),
4 headers: {
5 'Content-Type': 'application/json'
6 }
7}).then(res => res.json())
8 .then(data => console.log(data))
9 .catch(err => console.error("Error:", err));
Now that we are familiar with fetch()
, let's use it in our submitForm() method.
1submitForm = e => {
2 e.preventDefault();
3 this.setState({ isSubmitting: true });
4 fetch("https://61m46.sse.codesandbox.io/login", {
5 method: "POST",
6 body: JSON.stringify(this.state.values),
7 headers: {
8 "Content-Type": "application/json"
9 }
10 })
11 .then(res => {
12 this.setState({ isSubmitting: false });
13 return res.json();
14 })
15 .then(data => {
16 console.log(data);
17 !data.hasOwnProperty("error")
18 ? this.setState({ message: data.success })
19 : this.setState({ message: data.error, isError: true });
20 });
I'm not a big fan of the callbacks - .then().then().then(), I prefer async-await. Async/Await is a special syntax for handling Promises.
The async
keyword is placed before the function, to instruct JavaScript that it is an asynchronous function and will return a promise. Even if the function returns a non-promise value, JavaScript will still wrap that value in a resolved promise.
The await
keyword makes the JavaScript wait until the Promise is resolved or rejected before moving on to the next line of code to be executed.
1submitForm = async e => {
2 e.preventDefault();
3 this.setState({ isSubmitting: true });
4 const res = await fetch("https://61m46.sse.codesandbox.io/login", {
5 method: "POST",
6 body: JSON.stringify(this.state.values),
7 headers: {
8 "Content-Type": "application/json"
9 }
10 });
11 this.setState({ isSubmitting: false });
12 const data = await res.json();
13 !data.hasOwnProperty("error")
14 ? this.setState({ message: data.success })
15 : this.setState({ message: data.error, isError: true });
That was pretty easy, right? No messy syntax and bloating our application with jQuery. Have a look at the complete source code.
Let's combine the above-discussed code all together:
1import React, { Component } from "react";
2import ReactDOM from "react-dom";
3
4import "./styles.css";
5
6class SignInForm extends Component {
7 constructor(props) {
8 super(props);
9 this.state = {
10 values: {
11 email: "",
12 password: ""
13 },
14 isSubmitting: false,
15 isError: false
16 };
17 }
18
19 submitForm = async e => {
20 e.preventDefault();
21 console.log(this.state);
22 this.setState({ isSubmitting: true });
23
24 const res = await fetch("https://61m46.sse.codesandbox.io/login", {
25 method: "POST",
26 body: JSON.stringify(this.state.values),
27 headers: {
28 "Content-Type": "application/json"
29 }
30 });
31 this.setState({ isSubmitting: false });
32 const data = await res.json();
33 !data.hasOwnProperty("error")
34 ? this.setState({ message: data.success })
35 : this.setState({ message: data.error, isError: true });
36
37 setTimeout(
38 () =>
39 this.setState({
40 isError: false,
41 message: "",
42 values: { email: "", password: "" }
43 }),
44 1600
45 );
46 };
47
48 handleInputChange = e =>
49 this.setState({
50 values: { ...this.state.values, [e.target.name]: e.target.value }
51 });
52
53 render() {
54 return (
55 <div>
56 <form onSubmit={this.submitForm}>
57 <div className="input-group">
58 <label htmlFor="email">E-mail Address</label>
59 <input
60 type="email"
61 name="email"
62 id="email"
63 value={this.state.values.email}
64 onChange={this.handleInputChange}
65 title="Email"
66 required
67 />
68 </div>
69 <div className="input-group">
70 <label htmlFor="password">Password</label>
71 <input
72 type="password"
73 name="password"
74 id="password"
75 value={this.state.values.password}
76 onChange={this.handleInputChange}
77 title="password"
78 required
79 />
80 </div>
81 <button type="submit">Sign In</button>
82 </form>
83 <div className={`message ${this.state.isError && "error"}`}>
84 {this.state.isSubmitting ? "Submitting..." : this.state.message}
85 </div>
86 </div>
87 );
88 }
89}
90
91function App() {
92 return (
93 <div className="App">
94 <h1>Sign In To Your Account</h1>
95 <SignInForm />
96 </div>
97 );
98}
99
100const rootElement = document.getElementById("root");
101ReactDOM.render(<App />, rootElement);
The styling is not that fancy; the purpose of this code was to demonstrate form submission, and not the look of it.
1.App {
2 font-family: sans-serif;
3}
4.input-group {
5 margin-bottom: 10px;
6}
7.input-group label {
8 display: block;
9 margin-bottom: 5px;
10}
11button {
12 border: none;
13 padding: 8px 24px;
14}
15.message {
16 margin-top: 20px;
17 font-weight: 600;
18}
19.message.error {
20 color: red;
21}
The URL in the fetch()
may not work for you because the node container might be inactive. So, I suggest that if you are going to run this code, create your dummy API and use that URL in fetch()
. You can refer my nodejs code from down here:
1const app = require("express")();
2const cors = require("cors");
3const bodyParser = require("body-parser");
4
5app.use(cors());
6
7app.use(bodyParser.urlencoded({ extended: true }));
8app.use(bodyParser.json());
9
10app.get("/", (req, res) => {
11 res.send("Server running");
12});
13
14app.post("/login", (req, res) => {
15 const { email, password } = req.body;
16 if (email !== "[email protected]" || password !== "test")
17 return res.status(401).json({ error: "Invalid Credentials" });
18 res.json({ success: "Logged In successfully" });
19});
20
21const port = process.env.PORT || 8080;
22
23app.listen(port);
That is all for this guide; I hope you are going to experiment with some APIs out there. If you have any queries regarding this topic, feel free to contact me at CodeAlphabet. Cheers and happy coding!