How to Create and Deploy React Application On IIS-server

How to Create and Deploy React Application On IIS-server

This post to show you how to deploy the React App to the IIS - Server.

In this post, I am going to show you how to deploy the React App to the IIS - Server.

What is IIS?

IIS stands for "Internet Information Services", which is a web server provided by Microsoft to host the websites and other stuff on the web.

How to enable IIS?

If you have already enabled IIS then you can skip this step. But if you have not enabled it already then follow the below steps:

  1. Open Control Panel and then click on the "Programs and Features".
  2. Click on "Turn Windows features on or off".
  3. Select Internet Information Services and click on the OK button.
  4. To see whether or not IIS is enabled, press Windows + R key and type inetmgr and click on OK.
  5. IIS Manager is open.
Create a Simple React App

Open a command prompt or your favorite terminal and type the below command to create a react app.

npx create-react-app my-react-app  

After successfully creating the app go to the new app.

cd my-react-app  

To see how it look likes type the below command.

npm start 

and it will start the development server and navigate you to http://localhost:3000/

You can see the default landing page:

To host an app in any web server we first need to create a production build. To create a production build of our react app use the below command.

npm run build  

The output of the above command creates a new build folder inside the project which contains production build. So far we have created a React app & created a production build of that app. Now the next step is to deploy it on IIS. Press Windows + R key and write inetmgr to open the IIS Manager. You can see the below screen.

First, we will create a new Application Pool, so right-click on Application Pools and click on Add Application Pool. Then give it a name as you want and click on OK button.

After that right-click on the new app pool and select Advanced Settings. You will see the below window.

Then click on Identity and choose a Custom account and click on the set button and then add your windows credentials and click on OK.

After that right-click on Sites and then click on Add Website. Add the Site name and select application pool which we created earlier. After that under the physical path section, you have to give the path of build folder & also give the port number where you want to host.

Now right click on new website i.e ReactApp -> Manage Website -> Browse. Your react app is now successfully deployed.

Now the next step is to add routing in our react application. So I have created 2 components and also added react-router-dom package for routing. Here we are not going into detail about react routing.

Home page

Blog page

Create a production build again and try to browse the application which we hosted on IIS. You will see the application is working fine but now try to refresh the page and see what happens. You will get the below error.

So to fix this issue you have to install URL Rewrite module. After successful installation, you have to create a web.config file under public folder of app and copy-paste the below content into it.

<?xml version="1.0"?>  
<configuration>  
    <system.webServer>  
        <rewrite>  
            <rules>  
                <rule name="React Routes" stopProcessing="true">  
                    <match url=".*" />  
                    <conditions logicalGrouping="MatchAll">  
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />  
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />  
                        <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />  
                    </conditions>  
                    <action type="Rewrite" url="/" />  
                </rule>  
            </rules>  
        </rewrite>  
    </system.webServer>  
</configuration>     

Again build the application in production mode and browse. So now if you refresh the app you will not get an error and will be able to see the correct page. That's it -- so you have successfully created and deployed React application into the IIS server.

Conclusion

I hope that you have enjoyed this post, and please do not hesitate to send me your thoughts or comments about what could I have done better.

Thank you for reading and Happy Coding!

Angular 9 Tutorial: Learn to Build a CRUD Angular App Quickly

What's new in Bootstrap 5 and when Bootstrap 5 release date?

What’s new in HTML6

How to Build Progressive Web Apps (PWA) using Angular 9

What is new features in Javascript ES2020 ECMAScript 2020

How to Create Server Side Rendered React application using Next.js

How to Create Server Side Rendered React application using Next.js

React’s most popular code generator, Create React App, creates a client side rendered app, which means everyone that loads your page downloads the whole app and all front end code is ran on client side. One of the best options is Next.js.

Setting up a server side rendered app with the default code generated by Create React App is not easy. You have to do lots of changes to the default code to get anything working. Getting it to work exactly the way you want is even harder, so developers came up with some solutions. One of the best options is Next.js.

In this story, we will build an address book app, which uses those libraries, plus React Bootstrap, which has great integration with those libraries above to create forms. To start we need to run Next.js CLI to scaffold the app. We run npx create-next-app to create the app project folder with the initial files. The app will have a home page to display the contacts and let us open a modal to add a contact. There will be a table that displays all the contacts and Edit and Delete buttons on each row to edit or delete each contact. The contacts will store in a central Redux store to store the contacts in a central place, making them easy to access. React Router will be used for routing. Contacts will be saved in the back end spawned using the JSON server package.

For form validation, then you need to use a third-party library. Formik and Yup work great together to allow us to take care of most form validation needs. Formik let us build the forms and display the errors, and handle form value changes, which is another thing we have to do all my hand otherwise. Yup let us write a schema for validating our form fields. It can check almost anything, with common validation code like email and required fields available as built-in functions. It can also check for fields that depend on other fields, like the postal code format depending on the country. Bootstrap forms can be used seamlessly with Formik and Yup.

Once that is done, we have to install some libraries. To install the libraries we mentioned above, we run npm i axios bootstrap formik react-bootstrap react-redux react-router-dom yup . Axios is the HTTP client that we use for making HTTP requests to back end. react-router-dom is the package name for the latest version of React Router.

Now that we have all the libraries installed, we can start building the app. We create a store folder and create a file called actionCreator.js in it and add the following:

import { SET_CONTACTS } from './actions';

const setContacts = (contacts) => {
    return {
        type: SET_CONTACTS,
        payload: contacts
    }
};

export { setContacts };

This is the action creator for creating the action for storing the contacts in the store.

We create another file called actions.js in the same folder and add:

const SET_CONTACTS = 'SET_CONTACTS';

export { SET_CONTACTS };

This just have the type constant for dispatching the action.

Then in the store folder, we create index.js and add:

import { contactsReducer } from "./reducers";
import { createStore, combineReducers } from "redux";

const addressBookApp = combineReducers({
  contacts: contactsReducer,
});

const makeStore = (initialState, options) => {
  return createStore(addressBookApp, initialState);
};

export { makeStore };

We will use it in the main entry point file, which will be called _app.js in the pages folder to allow us to use the same Redux store in this multi-page, server side rendered app.

Then we make a file called reducers.js , and add:

import { SET_CONTACTS } from './actions';

function contactsReducer(state = {}, action) {
    switch (action.type) {
        case SET_CONTACTS:
            state = JSON.parse(JSON.stringify(action.payload));
            return state;
        default:
            return state
    }
}

export { contactsReducer };

This is the reducer where we store the contacts that we dispatch by calling the prop provided by the mapDispatchToProps function in our components.

Next we add some code files to the pages folder.

In index.js , we replace what is existing with the following:

import React from "react";
import Head from "next/head";
import { Router, Route } from "react-router-dom";
import { createMemoryHistory as createHistory } from "history";
import Navbar from "react-bootstrap/Navbar";
import Nav from "react-bootstrap/Nav";
import HomePage from "./HomePage";
import { contactsReducer } from "../store/reducers";
import { Provider } from "react-redux";
import { createStore, combineReducers } from "redux";

const history = createHistory();

const addressBookApp = combineReducers({
  contacts: contactsReducer,
});

const store = createStore(addressBookApp);

const Home = () => (
  <div>
    <Head>
      <title>Address Book</title>
      <link
			
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
        rel="stylesheet"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
        crossOrigin="anonymous"
      />
    </Head>
    <div className="App">
      <Router history={history}>
        <Navbar bg="primary" expand="lg" variant="dark">
          <Navbar.Brand href="#home">Address Book App</Navbar.Brand>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="mr-auto">
              <Nav.Link href="/">Home</Nav.Link>
            </Nav>
          </Navbar.Collapse>
        </Navbar>
        <Route path="/" exact component={HomePage} />
      </Router>
    </div>
    <style jsx>{`
      .App {
        text-align: center;
      }
			
    `}</style>
  </div>
);

export default Home;

This is where we add the navigation bar and show our routes routed by the React Router. In the styles element, we replace the existing code with:

.App {
  text-align: center;
}

to center some text.

Next we build our contact form. This is the most logic heavy part of our app. We create a file called ContactForm.js in the components folder and add:

import React from 'react';
import { Formik } from 'formik';
import Form from 'react-bootstrap/Form';
import Col from 'react-bootstrap/Col';
import InputGroup from 'react-bootstrap/InputGroup';
import Button from 'react-bootstrap/Button';
import * as yup from 'yup';
import { COUNTRIES } from '../helpers/exports';
import PropTypes from 'prop-types';
import { addContact, editContact, getContacts } from '../helpers/requests';
import { connect } from 'react-redux';
import { setContacts } from '../store/actionCreators';

const schema = yup.object({
  firstName: yup.string().required('First name is required'),
  lastName: yup.string().required('Last name is required'),
  address: yup.string().required('Address is required'),
  city: yup.string().required('City is required'),
  region: yup.string().required('Region is required'),
  country: yup.string().required('Country is required').default('Afghanistan'),
  postalCode: yup
    .string()
    .when('country', {
      is: 'United States',
      then: yup.string().matches(/^[0-9]{5}(?:-[0-9]{4})?$/, 'Invalid postal code'),
    })
    .when('country', {
      is: 'Canada',
      then: yup.string().matches(/^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$/, 'Invalid postal code'),
    })
    .required(),
  phone: yup
    .string()
    .when('country', {
      is: country => ["United States", "Canada"].includes(country),
      then: yup.string().matches(/^[2-9]\d{2}[2-9]\d{2}\d{4}$/, 'Invalid phone nunber')
    })
    .required(),
  email: yup.string().email('Invalid email').required('Email is required'),
  age: yup.number()
    .required('Age is required')
    .min(0, 'Minimum age is 0')
    .max(200, 'Maximum age is 200'),
});

function ContactForm({
  edit,
  onSave,
  setContacts,
  contact,
  onCancelAdd,
  onCancelEdit,
}) {
  const handleSubmit = async (evt) => {
    const isValid = await schema.validate(evt);
    if (!isValid) {
      return;
    }
    if (!edit) {
      await addContact(evt);
    }
    else {
      await editContact(evt);
    }
    const response = await getContacts();
    setContacts(response.data);
    onSave();
  }
	
return (
    <div className="form">
      <Formik
        validationSchema={schema}
        onSubmit={handleSubmit}
        initialValues={contact || {}}
      >
        {({
          handleSubmit,
          handleChange,
          handleBlur,
          values,
          touched,
          isInvalid,
          errors,
        }) => (
            <Form noValidate onSubmit={handleSubmit}>
              <Form.Row>
                <Form.Group as={Col} md="12" controlId="firstName">
                  <Form.Label>First name</Form.Label>
                  <Form.Control
                    type="text"
                    name="firstName"
                    placeholder="First Name"
                    value={values.firstName || ''}
                    onChange={handleChange}
                    isInvalid={touched.firstName && errors.firstName}
                  />
                  <Form.Control.Feedback type="invalid">
                    {errors.firstName}
                  </Form.Control.Feedback>
                </Form.Group>
                <Form.Group as={Col} md="12" controlId="lastName">
                  <Form.Label>Last name</Form.Label>
                  <Form.Control
                    type="text"
                    name="lastName"
                    placeholder="Last Name"
                    value={values.lastName || ''}
                    onChange={handleChange}
                    isInvalid={touched.firstName && errors.lastName}
                  />
									
<Form.Control.Feedback type="invalid">
                    {errors.lastName}
                  </Form.Control.Feedback>
                </Form.Group>
                <Form.Group as={Col} md="12" controlId="address">
                  <Form.Label>Address</Form.Label>
                  <InputGroup>
                    <Form.Control
                      type="text"
                      placeholder="Address"
                      aria-describedby="inputGroupPrepend"
                      name="address"
                      value={values.address || ''}
                      onChange={handleChange}
                      isInvalid={touched.address && errors.address}
                    />
                    <Form.Control.Feedback type="invalid">
                      {errors.address}
                    </Form.Control.Feedback>
                  </InputGroup>
                </Form.Group>
              </Form.Row>
              <Form.Row>
                <Form.Group as={Col} md="12" controlId="city">
                  <Form.Label>City</Form.Label>
                  <Form.Control
                    type="text"
                    placeholder="City"
                    name="city"
                    value={values.city || ''}
                    onChange={handleChange}
                    isInvalid={touched.city && errors.city}
                  />
									
<Form.Control.Feedback type="invalid">
                    {errors.city}
                  </Form.Control.Feedback>
                </Form.Group>
                <Form.Group as={Col} md="12" controlId="region">
                  <Form.Label>Region</Form.Label>
                  <Form.Control
                    type="text"
                    placeholder="Region"
                    name="region"
                    value={values.region || ''}
                    onChange={handleChange}
                    isInvalid={touched.region && errors.region}
                  />
                  <Form.Control.Feedback type="invalid">
                    {errors.region}
                  </Form.Control.Feedback>
                </Form.Group>
								
<Form.Group as={Col} md="12" controlId="country">
                  <Form.Label>Country</Form.Label>
                  <Form.Control
                    as="select"
                    placeholder="Country"
                    name="country"
                    onChange={handleChange}
                    value={values.country || ''}
                    isInvalid={touched.region && errors.country}>
                    {COUNTRIES.map(c => <option key={c} value={c}>{c}</option>)}
                  </Form.Control>
                  <Form.Control.Feedback type="invalid">
                    {errors.country}
                  </Form.Control.Feedback>
                </Form.Group>
								
<Form.Group as={Col} md="12" controlId="postalCode">
                  <Form.Label>Postal Code</Form.Label>
                  <Form.Control
                    type="text"
                    placeholder="Postal Code"
                    name="postalCode"
                    value={values.postalCode || ''}
                    onChange={handleChange}
                    isInvalid={touched.postalCode && errors.postalCode}
                  />
									
<Form.Control.Feedback type="invalid">
                    {errors.postalCode}
                  </Form.Control.Feedback>
                </Form.Group>
								
<Form.Group as={Col} md="12" controlId="phone">
                  <Form.Label>Phone</Form.Label>
                  <Form.Control
                    type="text"
                    placeholder="Phone"
                    name="phone"
                    value={values.phone || ''}
                    onChange={handleChange}
                    isInvalid={touched.phone && errors.phone}
                  />
									
<Form.Control.Feedback type="invalid">
                    {errors.phone}
                  </Form.Control.Feedback>
                </Form.Group>
								
<Form.Group as={Col} md="12" controlId="email">
                  <Form.Label>Email</Form.Label>
                  <Form.Control
                    type="text"
                    placeholder="Email"
                    name="email"
                    value={values.email || ''}
                    onChange={handleChange}
                    isInvalid={touched.email && errors.email}
                  />
									
<Form.Control.Feedback type="invalid">
                    {errors.email}
                  </Form.Control.Feedback>
                </Form.Group>
								
<Form.Group as={Col} md="12" controlId="age">
                  <Form.Label>Age</Form.Label>
                  <Form.Control
                    type="text"
                    placeholder="Age"
                    name="age"
                    value={values.age || ''}
                    onChange={handleChange}
                    isInvalid={touched.age && errors.age}
                  />
									
<Form.Control.Feedback type="invalid">
                    {errors.age}
                  </Form.Control.Feedback>
                </Form.Group>
              </Form.Row>
              <Button type="submit" style={{ 'marginRight': '10px' }}>Save</Button>
              <Button type="button" onClick={edit ? onCancelEdit : onCancelAdd}>Cancel</Button>
            </Form>
          )}
      </Formik>
    </div>
  );
}

ContactForm.propTypes = {
  edit: PropTypes.bool,
  onSave: PropTypes.func,
  onCancelAdd: PropTypes.func,
  onCancelEdit: PropTypes.func,
  contact: PropTypes.object
}

const mapStateToProps = state => {
  return {
    contacts: state.contacts,
  }
}
const mapDispatchToProps = dispatch => ({
  setContacts: contacts => dispatch(setContacts(contacts))
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ContactForm);

We use Formik to facilitate building our contact form here, with our Boostrap Form component nested in the Formik component so that we can use Formik’s handleChange , handleSubmit , values , touched and errors parameters. handleChange is a function that let us update the form field data from the inputs without writing the code ourselves. handleSubmit is the function that we passed into the onSubmit handler of the Formik component. The parameter in the function is the data we entered, with the field name as the key, as defined by the name attribute of each field and the value of each field as the value of those keys. Notice that in each value prop, we have ||'' so we do not get undefined values and prevent uncontrolled form warnings from getting triggered.

To display form validation messages, we have to pass in the isInvalid prop to each Form.Control component. The schema object is what Formik will check against for form validation. The argument in the required function is the validation error message. The second argument of the matches , min and max functions are also validation messages.

The parameter of the ContactForm function are props, which we will pass in from the HomePage component that we will build later. The handleSubmit function checks if the data is valid, then if it is then it will proceed to saving according to whether it is adding or editing a contact. Then when saving is successful we set the contacts in the store and call onSave prop, which is a function to close the modal the form is in. The modal will be defined in the home page.

mapStateToProps is a function provided by React Redux so that we can map the state directly to the props of our component as the function name suggests. mapDispatchToProps allows us to call function in the props of the component called setContacts to dispatch the action as we defined in actionCreators.js .

Next we create a file called exports.js after creating the helpers folder, and put:

export const COUNTRIES = [
  "Afghanistan",
  "Albania",
  "Algeria",
  "Andorra",
  "Angola",
  "Anguilla",
  "Antigua &amp; Barbuda",
  "Argentina",
  "Armenia",
  "Aruba",
  "Australia",
  "Austria",
  "Azerbaijan",
  "Bahamas",
  "Bahrain",
  "Bangladesh",
  "Barbados",
  "Belarus",
  "Belgium",
  "Belize",
  "Benin",
  "Bermuda",
  "Bhutan",
  "Bolivia",
  "Bosnia &amp; Herzegovina",
  "Botswana",
  "Brazil",
  "British Virgin Islands",
  "Brunei",
  "Bulgaria",
  "Burkina Faso",
  "Burundi",
  "Cambodia",
  "Cameroon",
  "Canada",
  "Cape Verde",
  "Cayman Islands",
  "Chad",
  "Chile",
  "China",
  "Colombia",
  "Congo",
  "Cook Islands",
  "Costa Rica",
  "Cote D Ivoire",
  "Croatia",
  "Cruise Ship",
  "Cuba",
  "Cyprus",
  "Czech Republic",
  "Denmark",
  "Djibouti",
  "Dominica",
  "Dominican Republic",
  "Ecuador",
  "Egypt",
  "El Salvador",
  "Equatorial Guinea",
  "Estonia",
  "Ethiopia",
  "Falkland Islands",
  "Faroe Islands",
  "Fiji",
  "Finland",
  "France",
  "French Polynesia",
  "French West Indies",
  "Gabon",
  "Gambia",
  "Georgia",
  "Germany",
  "Ghana",
  "Gibraltar",
  "Greece",
  "Greenland",
  "Grenada",
  "Guam",
  "Guatemala",
  "Guernsey",
  "Guinea",
  "Guinea Bissau",
  "Guyana",
  "Haiti",
  "Honduras",
  "Hong Kong",
  "Hungary",
  "Iceland",
  "India",
  "Indonesia",
  "Iran",
  "Iraq",
  "Ireland",
  "Isle of Man",
  "Israel",
  "Italy",
  "Jamaica",
  "Japan",
  "Jersey",
  "Jordan",
  "Kazakhstan",
  "Kenya",
  "Kuwait",
  "Kyrgyz Republic",
  "Laos",
  "Latvia",
  "Lebanon",
  "Lesotho",
  "Liberia",
  "Libya",
  "Liechtenstein",
  "Lithuania",
  "Luxembourg",
  "Macau",
  "Macedonia",
  "Madagascar",
  "Malawi",
  "Malaysia",
  "Maldives",
  "Mali",
  "Malta",
  "Mauritania",
  "Mauritius",
  "Mexico",
  "Moldova",
  "Monaco",
  "Mongolia",
  "Montenegro",
  "Montserrat",
  "Morocco",
  "Mozambique",
  "Namibia",
  "Nepal",
  "Netherlands",
  "Netherlands Antilles",
  "New Caledonia",
  "New Zealand",
  "Nicaragua",
  "Niger",
  "Nigeria",
  "Norway",
  "Oman",
  "Pakistan",
  "Palestine",
  "Panama",
  "Papua New Guinea",
  "Paraguay",
  "Peru",
  "Philippines",
  "Poland",
  "Portugal",
  "Puerto Rico",
  "Qatar",
  "Reunion",
  "Romania",
  "Russia",
  "Rwanda",
  "Saint Pierre &amp; Miquelon",
  "Samoa",
  "San Marino",
  "Satellite",
  "Saudi Arabia",
  "Senegal",
  "Serbia",
  "Seychelles",
  "Sierra Leone",
  "Singapore",
  "Slovakia",
  "Slovenia",
  "South Africa",
  "South Korea",
  "Spain",
  "Sri Lanka",
  "St Kitts &amp; Nevis",
  "St Lucia",
  "St Vincent",
  "St. Lucia",
  "Sudan",
  "Suriname",
  "Swaziland",
  "Sweden",
  "Switzerland",
  "Syria",
  "Taiwan",
  "Tajikistan",
  "Tanzania",
  "Thailand",
  "Timor L'Este",
  "Togo",
  "Tonga",
  "Trinidad &amp; Tobago",
  "Tunisia",
  "Turkey",
  "Turkmenistan",
  "Turks &amp; Caicos",
  "Uganda",
  "Ukraine",
  "United Arab Emirates",
  "United Kingdom",
  "United States",
  "United States Minor Outlying Islands",
  "Uruguay",
  "Uzbekistan",
  "Venezuela",
  "Vietnam",
  "Virgin Islands (US)",
  "Yemen",
  "Zambia",
  "Zimbabwe",
];

These are countries for the countries field in the form.

Then we make a file called requests.js in the same folder, and add:

const APIURL = 'http://localhost:3000';
const axios = require('axios');

export const getContacts = () => axios.get(`${APIURL}/contacts`);

export const addContact = (data) => axios.post(`${APIURL}/contacts`, data);

export const editContact = (data) => axios.put(`${APIURL}/contacts/${data.id}`, data);

export const deleteContact = (id) => axios.delete(`${APIURL}/contacts/${id}`);

These are functions are making our HTTP requests to the back end to save and delete contacts.

In HomePage.js , we put:

import React from 'react';
import { useState, useEffect } from 'react';
import Table from 'react-bootstrap/Table'
import ButtonToolbar from 'react-bootstrap/ButtonToolbar';
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal'
import ContactForm from './ContactForm';
import './HomePage.css';
import { connect } from 'react-redux';
import { getContacts, deleteContact } from './requests';

function HomePage() {
  const [openAddModal, setOpenAddModal] = useState(false);
  const [openEditModal, setOpenEditModal] = useState(false);
  const [initialized, setInitialized] = useState(false);
  const [selectedId, setSelectedId] = useState(0);
  const [selectedContact, setSelectedContact] = useState({});
  const [contacts, setContacts] = useState([]);
	
  const openModal = () => {
    setOpenAddModal(true);
  }
	
  const closeModal = () => {
    setOpenAddModal(false);
    setOpenEditModal(false);
    getData();
  }
	
  const cancelAddModal = () => {
    setOpenAddModal(false);
  }
	
  const editContact = (contact) => {
    setSelectedContact(contact);
    setOpenEditModal(true);
  }
	
  const cancelEditModal = () => {
    setOpenEditModal(false);
  }
	
  const getData = async () => {
    const response = await getContacts();
    setContacts(response.data);
    setInitialized(true);
  }
	
  const deleteSelectedContact = async (id) => {
    await deleteContact(id);
    getData();
  }
	
  useEffect(() => {
    if (!initialized) {
      getData();
    }
  })
	
  return (
    <div className="home-page">
      <h1>Contacts</h1>
      <Modal show={openAddModal} onHide={closeModal} >
        <Modal.Header closeButton>
          <Modal.Title>Add Contact</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <ContactForm edit={false} onSave={closeModal.bind(this)} onCancelAdd={cancelAddModal} />
        </Modal.Body>
      </Modal>
			
<Modal show={openEditModal} onHide={closeModal}>
        <Modal.Header closeButton>
          <Modal.Title>Edit Contact</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <ContactForm edit={true} onSave={closeModal.bind(this)} contact={selectedContact} onCancelEdit={cancelEditModal} />
        </Modal.Body>
      </Modal>
      <ButtonToolbar onClick={openModal}>
        <Button variant="outline-primary">Add Contact</Button>
      </ButtonToolbar>
      <br />
      <Table striped bordered hover>
        <thead>
          <tr>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Address</th>
            <th>City</th>
            <th>Country</th>
            <th>Postal Code</th>
            <th>Phone</th>
            <th>Email</th>
            <th>Age</th>
            <th>Edit</th>
            <th>Delete</th>
          </tr>
        </thead>
        <tbody>
          {contacts.map(c => (
            <tr key={c.id}>
              <td>{c.firstName}</td>
              <td>{c.lastName}</td>
              <td>{c.address}</td>
              <td>{c.city}</td>
              <td>{c.country}</td>
              <td>{c.postalCode}</td>
              <td>{c.phone}</td>
              <td>{c.email}</td>
              <td>{c.age}</td>
              <td>
                <Button variant="outline-primary" onClick={editContact.bind(this, c)}>Edit</Button>
              </td>
              <td>
                <Button variant="outline-primary" onClick={deleteSelectedContact.bind(this, c.id)}>Delete</Button>
              </td>
            </tr>
          ))}
        </tbody>
      </Table>
    </div>
  );
}

const mapStateToProps = state => {
  return {
    contacts: state.contacts,
  }
}

export default connect(
  mapStateToProps,
  null
)(HomePage);

It has the table to display the contacts and buttons to add, edit, and delete contacts. It gets data on the first load with the getData function call in the useEffect’s callback function. useEffect’s callback is called on every render so we want to set a initialized flag and check that it loads only if it’s true .

Note that we pass in all the props in this component to the ContactForm component. To pass an argument a onClick handler function, we have to call bind on the function and pass in the argument for the function as a second argument to bind . For example, in this file, we have editContact.bind(this, c) , where c is the contact object. The editContact function is defined as follows:

const editContact = (contact) => {
    setSelectedContact(contact);
    setOpenEditModal(true);
  }

c is the contact parameter we pass in.

In the styles block, we have:

.home-page {
  padding: 20px;
}

to add some padding.

In index.js in the pages folder, we replace the existing code with:

import React from "react";
import Head from "next/head";
import { Router, Route } from "react-router-dom";
import { createMemoryHistory as createHistory } from "history";
import Navbar from "react-bootstrap/Navbar";
import Nav from "react-bootstrap/Nav";
import HomePage from "./HomePage";
import { contactsReducer } from "../store/reducers";
import { Provider } from "react-redux";
import { createStore, combineReducers } from "redux";

const history = createHistory();

const addressBookApp = combineReducers({
  contacts: contactsReducer,
});

const store = createStore(addressBookApp);

const Home = () => (
  <div>
    <Head>
      <title>Address Book</title>
      <link
			
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
        rel="stylesheet"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
        crossOrigin="anonymous"
      />
    </Head>
    <div className="App">
      <Router history={history}>
        <Navbar bg="primary" expand="lg" variant="dark">
          <Navbar.Brand href="#home">Address Book App</Navbar.Brand>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="mr-auto">
              <Nav.Link href="/">Home</Nav.Link>
            </Nav>
          </Navbar.Collapse>
        </Navbar>
        <Route path="/" exact component={HomePage} />
      </Router>
    </div>
		
    <style jsx>{`
      .App {
        text-align: center;
      }
    `}</style>
  </div>
);

export default Home;

This is the entry point of the app, we add the navigation menu here and also the route for the home page here. Since we do not have an index.html in a server side rendered app, we render the head tag of the page by putting the Head component here, along with the title and link components inside the Head . We include these to change the title and add the Bootstrap stylesheet respectively.

We have to add a file called _app.js in the pages folder to let us use our Redux store in all our components since this is not a normal client side rendered app. This file overrides the default App class in Next.js . The class is used for loading initialization code in our pages. There is no ReactDOM.render call with the topmost component where we can wrap the Provider component around it to let us use our Redux store everywhere, so we have to add:

// pages/_app.js
import React from "react";
import { Provider } from "react-redux";
import App, { Container } from "next/app";
import withRedux from "next-redux-wrapper";
import { contactsReducer } from "../store/reducers";
import { createStore, combineReducers } from "redux";

const addressBookApp = combineReducers({
  contacts: contactsReducer,
});

const makeStore = (initialState, options) => {
  return createStore(addressBookApp, initialState);
};

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    const pageProps = Component.getInitialProps
      ? await Component.getInitialProps(ctx)
      : {};
			
    return { pageProps };
  }
	
  render() {
    const { Component, pageProps, store } = this.props;
    return (
      <Container>
        <Provider store={store}>
          <Component {...pageProps} />
        </Provider>
      </Container>
    );
  }
}

export default withRedux(makeStore)(MyApp);

to wrap our Redux store around all our components. Component is any component in our app. We use the next-redux-wrapper package to pass the store object down to all of our components by allowing us to wrap Provider with the store prop around our components.

Now we can run the app by running npm run build then npm run start -- --port 3001 .

To start back end, we first install the json-server package by running npm i json-server . Them go to our project folder and run:

json-server --watch db.json

In db.json , change the text to:

{
  "contacts": [
  ]
}

so that we have the contacts endpoints defined in requests.js available.

At the end, we have the following:

Thank for visiting and reading this article! I'm highly appreciate your actions! Please share if you liked it!

How to Build the Next Generation of Forms with React Hooks Forms

How to Build the Next Generation of Forms with React Hooks Forms

Performant, flexible, and extensible forms, easy to use with validation by React Hooks

Drag and Drop Builder. You can build your own form with auto-generated code here at the React Hook Form Website. You will be able to re-arrange using drag and drop, delete, and edit each field to start using this incredible plugin, without having to read any documentation, simply by copying that code.

Why Not Other React Library Forms?

It’s really simple, there are multiple good reasons:

  1. Easy to adopt as form state is inherently local, it can be easily adopted without other dependencies.

  2. Reduces the code to handle forms, with less complexity due to the Hooks. You can find a complete code comparison here.

  3. Performance is important and package size matters. This is a tiny library without any dependencies.

  4. Minimizes the number of re-renders and faster mount, striving to provide the best user experience. Twenty times less than other packages like Formik or Redux Form

Installation

Installing React Hook Form only takes a single command and you’re ready to roll. If you are using npm:

npm install react-hook-form

Or, if you are using Yarn:

yarn add react-hook-form
Basic Usage

The following code will demonstrate basic usage.

The main component used is the useForm Hook with the returned functions and variables:

  • register: To connect a field to rules or validation functions.
  • handleSubmit: To check and validate all fields before sending submit.
  • watch: This will watch specified inputs and return their value.
  • errors: Contains form errors or error messages that belong to each input.
import React from 'react'
import useForm from 'react-hook-form'

export default function App() {
  const { register, handleSubmit, watch, errors } = useForm()
  const onSubmit = data => { console.log(data) }

  console.log(watch('example')) // watch input value by passing the name of it

  return (
    {/* "handleSubmit" will validate your inputs before invoking "onSubmit" */}
    <form onSubmit={handleSubmit(onSubmit)}>
    {/* register your input into the hook by invoking the "register" function */}
      <input name="example" defaultValue="test" ref={register} />
      
      {/* include validation with required or other standard HTML validation rules */}
      <input name="exampleRequired" ref={register({ required: true })} />
      {/* errors will return when field validation fails  */}
      {errors.exampleRequired && <span>This field is required</span>}
      
      <input type="submit" />
    </form>
  )
}
Register Fields

Each field needs a specific unique name that you will also use for labels and then you will pass the register Hook to the ref element.

Inside it, you will pass multiple parameters. Required is needed to tell if the user has to enter that field and then you will be able to easily use other standard HTML rules.

Here’s the list of validation rules supported:

  • required
  • min
  • max
  • minLength
  • maxLength
  • pattern
  • validate
import React from 'react'
import useForm from 'react-hook-form'

export default function App() {
  const { register, handleSubmit } = useForm()
  const onSubmit = data => console.log(data)
   
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={register({ required: true, maxlength: 20 })} />
      <input name="lastName" ref={register({ pattern: /^[A-Za-z]+$/i })} />
      <input name="age" type="number" ref={register({ min: 18, max: 99 })} />
      <input type="submit" />
    </form>
  );
}

The validate function is a great way to use custom logic specific to that field, enabling you to implement custom behavior very easily.

<input
  name="single"
  ref={
    register({
      validate: (value) => value === '1'
    })
  }
/>
Handle Fields Errors

React Hook Form provides an errors object to show you the errors within the form related to each unique field.

import React from 'react'
import useForm from 'react-hook-form'

export default function App() {
  const { register, errors } = useForm()
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Input name="firstName" ref={register({ required: true })} />
      {errors.firstName && 'First name is required'}
      <Input name="lastName" ref={register({ required: true })} />
      {errors.lastName && 'Last name is required'}
      <input type="submit" />
    </form>
  );
}
Drag and Drop Builder

You can build your own form with auto-generated code here at the React Hook Form Website.

You will be able to re-arrange using drag and drop, delete, and edit each field to start using this incredible plugin, without having to read any documentation, simply by copying that code.

You can easily build a form like this one in less than one minute!

import React from 'react';
import useForm from 'react-hook-form';

export default function App() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = data => console.log(data);
  console.log(errors);
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input type="text" placeholder="First name" name="First name" ref={register({required: true, maxLength: 80})} />
      <input type="text" placeholder="Last name" name="Last name" ref={register({required: true, maxLength: 100})} />
      <input type="text" placeholder="Email" name="Email" ref={register({required: true, pattern: /^\[email protected]\S+$/i})} />
      <input type="tel" placeholder="Mobile number" name="Mobile number" ref={register({required: true, minLength: 6, maxLength: 12})} />
      <select name="Title" ref={register({ required: true })}>
        <option value="Mr">Mr</option>
        <option value="Mrs">Mrs</option>
        <option value="Miss">Miss</option>
        <option value="Dr">Dr</option>
      </select>

      <input name="Developer" type="radio" value="Yes" ref={register({ required: true })}/>
      <input name="Developer" type="radio" value="No" ref={register({ required: true })}/>

      <input type="submit" />
    </form>
  );
}

I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others. Thank you!

15 Common Mistakes Developers Made While writing JavaScript Apps

15 Common Mistakes Developers Made While writing JavaScript Apps

Every developer make mistake some time when writing apps. This is a normal part of the development process. In this post, we'll learn 15 Common Mistakes Developers Made While Writing JavaScript Apps hope this post will help you

Common Mistakes Developers Made While Writing JavaScript Apps

Every developer make mistake some time when writing apps. This is a normal part of the development process. There are some mistakes that are made more often than others. It is good to be aware of them so that they can be corrected before it’s made. Once we can do that then we can develop apps a lot easier and become a proficient JavaScript developer since we can develop apps that makes less bugs. We will go through some of the more common bugs that are made so we can avoid them here

1. Confusing the Equals

In JavaScript, single equal, double equal, and tripe equal all have their own meanings. Single equal sign is the assignment operator which assigns the value on the left to the variable to the right. Double equal sign is the equality check operator which checks an object’s content for equality without checking its type. The triple equals operator checks an object’s content and the type for equality.

We use the single equal assignment operator like the following:

let a = 1

This is used for setting variable values, so it’s we use single equal in a place that shouldn’t be used like in:

if (a = 1){ ... }

then we would be assigning 1 to a which is always true . This means that the code inside the if statement always runs. That’s definitely not what we want.

Double equal sign shouldn’t be too too much since it doesn’t check the type of the object when checking for equality, so something like:

1 == '1'

if true . This creates problems because if we are only checking for number 1 and we get string with 1 in it, it’s still true. We want to convert them to the same type and then compare them with === to check for equality to avoid ambiguity. So if we want to compare if all forms of 1 are equal to each other we convert them to number first by using:

Number(1) === Number('1')

1 wouldn’t be equal to '1' is we use === since they are different types. This would make things a lot more clear. If we want to make sure something aren’t equal to each other then we can use !== to check if they don’t have the same content or the same type, so:

1 !== '1'

would be true .

2. Mismatching Brackets

Nested statements and functions in each other means that there’re multiple levels of brackets in each file. Usually, apps are pretty complex so the levels can add up. This means that mismatching brackets is easy if you use a text editor that doesn’t support syntax highlight or check for mismatched brackets. This can easily be avoided with modern text editors such as Visual Studio Code, Atom, and Sublime. If we want to use simpler text editors, then use linters and code formatting tools like ESLint and Prettier to detect these issues. They also let us format code automatically and detect common style issues that may occur like quote style inconsistencies, number of characters in a line, functions that can be shortened, etc.

3. Mismatching Quotes

JavaScript lets us use single quotes, double quotes, and backticks for strings. They are equivalent. However, we should open and close with the same character. So if we open a string with single quote then use single quote to close a string, and if we started with double quotes or backticks, then use those to close the string respectively. Also, special characters like quotation marks have to escape to be included in a string in some cases. If you open a string with single quotes, then if you use single quotes in a string, then you have to escape that to include it in the string. This also applies to double quotes and backticks. If you use double quotes in a double quoted string then you have to escape it. And if you use a backtick in a template string, then you have to escape the backtick character.

4. Parentheses

In if statements, parentheses always have to wrap around the whole condition. For example, something like:

if (x > y) && (y < 10) {...}

won’t work. The correct way to write that statement is to write is:

if ((x > y) && (y < 10)) {...}

if we want to check that both conditions are true.

5. Semicolon

Semicolons are optional at the end of a JavaScript line. However, to make things clear for other people, we should include it so that people know where a line ends. We can use a code linter or formatter like ESLint or Prettier to do this automatically. Lots of text editors also have add-ons to fix it automatically for you.

6. Capitalization

JavaScript code is case-sensitive, so things that have different capitalization will be considered different even if they have the same spelling. Anything that references them also have to be capitalized correctly. For example, getElementsByTagName should always be spelled this way with exact same capitalization. The general convention in JavaScript is that we spell variables and function names with camel case, so we should stick with that for consistency if we define our own variables.

7. Referencing Code That’s not Yet Loaded

It’s important that we reference code that have been defined and loaded before hand in order to use the code. If we are using script tag then before we reference the code, we have to load the code first. So the script tag that references the script with the variable we want to use should come before the script tag that references the script that has the code that we want to reference.

Fortunately, JavaScript modules are much more common nowadays, so that we just have to remember to export the code that you want to use in another module and the import the exported variable in the module that you want to use the variable before referencing it. JavaScript modules solves a lot problems with script tags. Global variables do not have to used much anymore to let different scripts reference the same variable, and also we can make variables private without the use of closures since we only need to export the ones that are needed elsewhere.

8. Variable Names

In JavaScript, there are many reserved words that cannot be used as variable names. They shouldn’t be used as variable names since they collide the name of the reserved words, creating confusion with the JavaScript interpreter. To avoid this we should use names that are descriptive like firstName , lastName , and things like that.

9. Scope

We shouldn’t use global variables whenever possible. This means that all variables we declare should use the let or const keywords for variables and constants respectively. This avoids issues with global variable scope and overwriting global variable data. It also let us avoid errors from assigning to entities that should be constant or assigning things accidentally that are global.

10. Missing or Unexpected Parameters

When functions are called with expected parameters missing, then unexpected results may be returned because you passed in unexpected input to a function.We have to make sure that we pass in the right parameters to a function so that we get the right results. It also a good idea to check for unexpected parameters if the function is used in lots of places like functions that are in libraries so that we can deal with unexpected parameters gracefully like ending the execution of the function when parameters passed in are of an invalid type or null or undefined .

11. Index Errors

JavaScript arrays starts with index 0, so the last index of an array will always be 1 less than the length of the array. When you pass in an index that is beyond the length or it’s invalid like a negative number, we get undefined , so we will get ReferenceErrors if we try to get the invalid entry and do stuff with it.

12. Null and Undefined

null and undefined are things that are often the values of variables. This means that we have to check for these when we are getting something by traversing the nested properties of objects or looping through an array. When we have null or undefined we want to handle them gracefully. This means that we should always check for them. So we if have an object called foo and we want to access deeply nested properties within it, then we should check for null or undefined in each level, like so:

if (foo && foo.bar && foo.bar.baz){ ... }

This way we know that all the properties are defined so that we can get access the baz property. For arrays if we want to access index i , we should check if it’s defined by writing:

if (arr[i]){...}

so that we won’t get unexpected undefined errors.

The optional chaining operator (?. ) is being worked on, so hopefully it will be finalized soon and we can use it to access deeply nested properties in an object and we don’t have to deal with properties being undefined as much anymore. Also, Lodash has a get function, which can try to access deeply properties of arrays and objects and get the value if it exists or return null if there’s anything undefined in the middle of the object’s hierarchy. This is much better than a long chain of undefined or null checks.

13. Confusing Undefined and Null

JavaScript has both undefined and null for non-values. However, there are quite a few differences between the two. undefined means that the variable may have been declared, but nothing is set to it. A variable can also be explicitly set as undefined . The type of an undefined variable, when checking the type with the typeof operator, will get us the type 'undefined'. Functions that don’t return anything returns undefined. On the other hand, null values have to be explicitly set by functions that return null or just set directly to a variable. When we check an object that has the null value set, we’ll find that the type of it is'object' if a variable has the null value.

For this reason, it’s probably easier to stick to undefined whenever we can when we’re setting variable values to non-values. It reduces confusion and we only have to check that the type of a variable is 'undefined' to see whether it’s undefined. That’s less painful than having two checks, for both null and undefined.

To write functions that return undefined, we don’t have to do anything like the following example:

const f = () => {}

To set a variable that was assigned some other value to undefined, we can write:

x = undefined;

To check if a property value is undefine, we can write:

typeof obj.prop === 'undefined'

or

obj.prop === undefined

To check if a variable is undefined, we can write the following code:

typeof x === 'undefined'

A declared variable that hasn’t been assigned anything automatically has the value undefined.

If we have to check for null, then we can write:

obj.prop === null

or

x === null

for variables. We can’t use the typeof operator for checking null because the data type of null is 'object'.

14. Confusing Addition and Concatenation

In JavaScript, the + operator is used for both adding two numbers and concatenating strings together. Because JavaScript is a dynamic language, the operands are all automatically converted to the same type before the operation is applied. For example, if we have:

let x = 1 + 1;

then we get two because they’re both numbers. The + operation was used for addition like we expected. However, if we have the following expression:

let x = 1 + '1';

then we get '11' because the first operand was coerced into a string before the + operation is applied. The + operation was used for concatenation instead of addition. When we use the + operator on multiple variables, this makes knowing the type even harder. For example, if we have:

let x = 1;
let y = 2;
let z = x + y;

as we expect, we get three because x and y are both numbers. On the other hand, if we have:

let x = 1;
let y = '2';
let z = x + y;

then we get '12' because y is a string, so the + operator was used for concatenation instead. To solve this issue, we should convert all the operands to numbers first before using them with the + operator. For example, we should rewrite the above example into the following:

let x = 1;
let y = '2';
let z = Number(x) + Number(y);

The code above will get us 3 as the value of z since we converted them both to numbers with the Number factory function first. The Number function takes in any object and returns a number if it can be parsed into a number, or NaN otherwise. An alternative way to do this is to use the new Number(...).valueOf() function, as we do in the following code:

let x = 1;
let y = '2';
let z = new Number(x).valueOf() + new Number(y).valueOf();

Since new Number(...) is a constructor that creates an object type, we want to use the valueOf function to convert it back to a primitive type to make sure that what we get is a number type. A shorter way to do this is to write:

let x = 1;
let y = '2';
let z = +x + +y;

The + sign in front of a single operand will try to convert the single operand into a number or toNaN if it can’t be converted into a number. It does the same thing as the Number function. We can also convert a variable to a particular type of number. The Number object has a parseInt function to convert an object into an integer and a parseFloat function to convert an object into a floating-point number. parseInt takes the object you want to convert to a number as the first argument. It also takes a radix as an optional second argument, which is the base of the mathematical numeral systems. If the string starts with 0x, then the radix will be set to 16. If the string starts with anything else, then the radix will be set to 10.

We can use them as in the following examples:

let x = 1;
let y = '2';
let z = Number.parseInt(x) + Number.parseInt(y)

Also, we can use the parseFloat function as in the following code:

let x = 1;
let y = '2';
let z = Number.parseFloat(x) + Number.parseFloat(y)

We will get 3 in both of the examples above.

15. Breaking Return Statements Into Multiple Lines

JavaScript closes a statement at the end, so one line code is considered distinct from the other. For example, if we have:

const add = (a, b) => {
  return
  a + b;
}

we get undefined if we run console.log(add(1, 2)); since we ran the return statement, which ended the function execution, before a + b is run. Therefore, a + b will never be run in this function. To fix this, we either have to put the return statement all in one line or use parentheses to surround what we want to return. For example, we can write:

const add = (a, b) => {
  return a + b;
}

This will log 3 if we run console.log(add(1, 2)); since we are actually returning the computed result in the function. We can also write:

const add = (a, b) => {
  return (
    a + b
  );
}

This is handy for returning expressions that might be longer than one line. This will also log 3 if we run console.log(add(1, 2));. For arrow functions, we can also write:

const add = (a, b) => a + b

for single-line functions since the return statement is implicit for single-line arrow functions. We can also write:

const add = (a, b) => (a + b)

to get the same thing. This also works for single-line arrow functions.

In JavaScript, if a statement is incomplete, like the first line of:

const power = (a) => {
  const
    power = 10;
  return a ** 10;
}

inside the function then the JavaScript interpreter will run the first line together with the second line to get the full statement. So:

const
  power = 10;

is the same as:

const power = 10;

However, for complete statements like return statements, the JavaScript interpreter will treat them as separate lines. So:

return 
  a ** 10;

is not the same as:

return a ** 10;

Even though JavaScript is a friendly language, it’s still very easy to make mistakes when writing JavaScript code. It’s easy to confuse undefined and null when we aren’t familiar with JavaScript. Because of the dynamic typing nature of JavaScript, operators like the + operator that can do multiple things can easily be converted to a type we don’t expect and produce the wrong result. Also, if statements can be complete on their own, then they shouldn’t be written in their own lines if we want both lines to be together.

Yes, that is all. I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others. Thank you !