One place for hosting & domains

      How To Build a Customer List Management App with React and TypeScript


      The author selected the Tech Education Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      TypeScript has brought a lot of improvement into how JavaScript developers structure and write code for apps, especially web applications. Defined as a superset of JavaScript, TypeScript behaves identically to JavaScript but with extra features designed to help developers build larger and more complex programs with fewer or no bugs. TypeScript is increasingly gaining popularity; adopted by major companies like Google for the Angular web framework. The Nest.js back-end framework was also built with TypeScript.

      One of the ways to improve productivity as a developer is the ability to implement new features as quickly as possible without any concern over breaking the existing app in production. To achieve this, writing statically typed code is a style adopted by many seasoned developers. Statically typed programming languages like TypeScript enforce an association for every variable with a data type; such as a string, integer, boolean, and so on. One of the major benefits of using a statically typed programming language is that type checking is completed at compile time, therefore developers can see errors in their code at a very early stage.

      React is an open-source JavaScript library, which developers use to create high-end user interfaces for scalable web applications. The great performance and dynamic user interfaces built with React for single-page applications make it a popular choice among developers.

      In this tutorial, you will create a customer list management application with a separate REST API backend and a frontend built with React and TypeScript. You will build the backend using a fake REST API named json-server. You’ll use it to quickly set up a CRUD (Create, Read, Update, and Delete) backend. Consequently you can focus on handling the front-end logic of an application using React and TypeScript.

      Prerequisites

      To complete this tutorial, you will need:

      Step 1 — Installing TypeScript and Creating the React Application

      In this step, you will install the TypeScript package globally on your machine by using the Node Package Manager (npm). After that, you will also install React and its dependencies, and check that your React app is working by running the development server.

      To begin, open a terminal and run the following command to install TypeScript:

      • npm install -g typescript

      Once the installation process is complete, execute the following command to check your installation of TypeScript:

      You will see the current version installed on your machine:

      Output

      Version 3.4.5

      Next, you will install the React application by using the create-react-app tool to set up the application with a single command. You'll use the npx command, which is a package runner tool that comes with npm 5.2+. The create-react-app tool has built-in support for working with TypeScript without any extra configuration required. Run the following command to create and install a new React application named typescript-react-app:

      • npx create-react-app typescript-react-app --typescript

      The preceding command will create a new React application with the name typescript-react-app. The --typescript flag will set the default filetype for React components to .tsx.

      Before you complete this section, the application will require moving from one port to another. To do that, you will need to install a routing library for your React application named React Router and its corresponding TypeScript definitions. You will use yarn to install the library and other packages for this project. This is because yarn is faster, especially for installing dependencies for a React application. Move into the newly created project folder and then install React Router with the following command:

      • cd typescript-react-app
      • yarn add react-router-dom

      You now have the React Router package, which will provide the routing functionality within your project. Next, run the following command to install the TypeScript definitions for React Router:

      • yarn add @types/react-router-dom

      Now you'll install axios, which is a promised-based HTTP client for browsers, to help with the process of performing HTTP requests from the different components that you will create within the application:

      Once the installation process is complete, start the development server with:

      Your application will be running on http://localhost:3000.

      React application homepage

      You have successfully installed TypeScript, created a new React application, and installed React Router in order to help with navigating from one page of the application to another. In the next section, you will set up the back-end server for the application.

      Step 2 — Creating a JSON Server

      In this step, you'll create a mock server that your React application can quickly connect with, as well as use its resources. It is important to note that this back-end service is not suitable for an application in production. You can use Nest.js, Express, or any other back-end technology to build a RESTful API in production. json-server is a useful tool whenever you need to create a prototype and mock a back-end server.

      You can use either npm or yarn to install json-server on your machine. This will make it available from any directory of your project whenever you might need to make use of it. Open a new terminal window and run this command to install json-server while you are still within the project directory:

      • yarn global add json-server

      Next, you will create a JSON file that will contain the data that will be exposed by the REST API. For the objects specified in this file (which you'll create), a CRUD endpoint will be generated automatically. To begin, create a new folder named server and then move into it:

      Now, use nano to create and open a new file named db.json:

      Add the following content to the file:

      /server/db.json

      {
          "customers": [
              {
                  "id": 1,
                  "first_name": "Customer_1",
                  "last_name": "Customer_11",
                  "email": "[email protected]",
                  "phone": "00000000000",
                  "address": "Customer_1 Address",
                  "description": "Customer_1 description"
              },
              {
                  "id": 2,
                  "first_name": "Customer_2",
                  "last_name": "Customer_2",
                  "email": "[email protected]",
                  "phone": "00000000000",
                  "address": "Customer_2 Adress",
                  "description": "Customer_2 Description"
              }
          ]
      }
      

      The JSON structure consists of a customer object, which has two datasets assigned. Each customer consists of seven properties: id, description, first_name, last_name, email, phone, and address.

      Save and exit the file.

      By default, the json-server runs on port 3000—this is the same port on which your React application runs. To avoid conflict, you can change the default port for the json-server. To do that, move to the root directory of the application:

      • cd ~/typescript-react-app

      Open the application with your preferred text editor and create a new file named json-server.json:

      Now insert the following to update the port number:

      /json-server.json

      {
          "port": 5000
      }
      

      This will act as the configuration file for the json-server and it will ensure that the server runs on the port specified in it at all times.

      Save and exit the file.

      To run the server, use the following command:

      • json-server --watch server/db.json

      This will start the json-server on port 5000. If you navigate to http://localhost:5000/customers in your browser, you will see the server showing your customer list.

      Customer list shown by json-server

      To streamline the process of running the json-server, you can update package.json with a new property named server to the scripts object as shown here:

      /package.json

      {
      ...
        "scripts": {
          "start": "react-scripts start",
          "build": "react-scripts build",
          "test": "react-scripts test",
          "eject": "react-scripts eject",
          "server": "json-server --watch server/db.json"
        },
      ...
      }
      

      Save and exit the file.

      Now anytime you wish to start the json-server, all you have to do is run yarn server from the terminal.

      You've created a simple REST API that you will use as the back-end server for this application. You also created a customer JSON object that will be used as the default data for the REST API. Lastly, you configured an alternative port for the back-end server powered by json-server. Next, you will build reusable components for your application.

      Step 3 — Creating Reusable Components

      In this section, you will create the required React components for the application. This will include components to create, display, and edit the details of a particular customer in the database respectively. You'll also build some of the TypeScript interfaces for your application.

      To begin, move back to the terminal where you have the React application running and stop the development server with CTRL + C. Next, navigate to the ./src/ folder:

      Then, create a new folder named components inside of it and move into the new folder:

      • mkdir components
      • cd components

      Within the newly created folder, create a customer folder and then move into it:

      • mkdir customer
      • cd customer

      Now create two new files named Create.tsx and Edit.tsx:

      • touch Create.tsx Edit.tsx

      These files are React reusable components that will render the forms and hold all the business logic for creating and editing the details of a customer respectively.

      Open the Create.tsx file in your text editor and add the following code:

      /src/components/customer/Create.tsx

      import * as React from 'react';
      import axios from 'axios';
      import { RouteComponentProps, withRouter } from 'react-router-dom';
      
      export interface IValues {
          first_name: string,
          last_name: string,
          email: string,
          phone: string,
          address: string,
          description: string,
      }
      export interface IFormState {
          [key: string]: any;
          values: IValues[];
          submitSuccess: boolean;
          loading: boolean;
      }
      
      

      Here you've imported React, axios, and other required components necessary for routing from the React Router package. After that you created two new interfaces named IValues and IFormState. TypeScript interfaces help to define the specific type of values that should be passed to an object and enforce consistency throughout an application. This ensures that bugs are less likely to appear in your program.

      Next, you will build a Create component that extends React.Component. Add the following code to the Create.tsx file immediately after the IFormState interface:

      /src/components/customer/Create.tsx

      ...
      class Create extends React.Component<RouteComponentProps, IFormState> {
          constructor(props: RouteComponentProps) {
              super(props);
              this.state = {
                  first_name: '',
                  last_name: '',
                  email: '',
                  phone: '',
                  address: '',
                  description: '',
                  values: [],
                  loading: false,
                  submitSuccess: false,
              }
          }
      }
      export default withRouter(Create)
      

      Here you've defined a React component in Typescript. In this case, the Create class component accepts props (short for “properties”) of type RouteComponentProps and uses a state of type IFormState. Then, inside the constructor, you initialized the state object and defined all the variables that will represent the rendered values for a customer.

      Next, add these methods within the Create class component, just after the constructor. You'll use these methods to process customer forms and handle all changes in the input fields:

      /src/components/customer/Create.tsx

      ...
                values: [],
                loading: false,
                submitSuccess: false,
            }
        }
      
        private processFormSubmission = (e: React.FormEvent<HTMLFormElement>): void => {
                e.preventDefault();
                this.setState({ loading: true });
                const formData = {
                    first_name: this.state.first_name,
                    last_name: this.state.last_name,
                    email: this.state.email,
                    phone: this.state.phone,
                    address: this.state.address,
                    description: this.state.description,
                }
                this.setState({ submitSuccess: true, values: [...this.state.values, formData], loading: false });
                axios.post(`http://localhost:5000/customers`, formData).then(data => [
                    setTimeout(() => {
                        this.props.history.push('/');
                    }, 1500)
                ]);
            }
      
            private handleInputChanges = (e: React.FormEvent<HTMLInputElement>) => {
                e.preventDefault();
                this.setState({
                    [e.currentTarget.name]: e.currentTarget.value,
            })
        }
      
      ...
      export default withRouter(Create)
      ...
      

      The processFormSubmission() method receives the details of the customer from the application state and posts it to the database using axios. The handleInputChanges() uses React.FormEvent to obtain the values of all input fields and calls this.setState() to update the state of the application.

      Next, add the render() method within the Create class component immediately after the handleInputchanges() method. This render() method will display the form to create a new customer in the application:

      /src/components/customer/Create.tsx

      ...
        public render() {
            const { submitSuccess, loading } = this.state;
            return (
                <div>
                    <div className={"col-md-12 form-wrapper"}>
                        <h2> Create Post </h2>
                        {!submitSuccess && (
                            <div className="alert alert-info" role="alert">
                                Fill the form below to create a new post
                        </div>
                        )}
                        {submitSuccess && (
                            <div className="alert alert-info" role="alert">
                                The form was successfully submitted!
                                </div>
                        )}
                        <form id={"create-post-form"} onSubmit={this.processFormSubmission} noValidate={true}>
                            <div className="form-group col-md-12">
                                <label htmlFor="first_name"> First Name </label>
                                <input type="text" id="first_name" onChange={(e) => this.handleInputChanges(e)} name="first_name" className="form-control" placeholder="Enter customer's first name" />
                            </div>
                            <div className="form-group col-md-12">
                                <label htmlFor="last_name"> Last Name </label>
                                <input type="text" id="last_name" onChange={(e) => this.handleInputChanges(e)} name="last_name" className="form-control" placeholder="Enter customer's last name" />
                            </div>
                            <div className="form-group col-md-12">
                                <label htmlFor="email"> Email </label>
                                <input type="email" id="email" onChange={(e) => this.handleInputChanges(e)} name="email" className="form-control" placeholder="Enter customer's email address" />
                            </div>
                            <div className="form-group col-md-12">
                                <label htmlFor="phone"> Phone </label>
                                <input type="text" id="phone" onChange={(e) => this.handleInputChanges(e)} name="phone" className="form-control" placeholder="Enter customer's phone number" />
                            </div>
                            <div className="form-group col-md-12">
                                <label htmlFor="address"> Address </label>
                                <input type="text" id="address" onChange={(e) => this.handleInputChanges(e)} name="address" className="form-control" placeholder="Enter customer's address" />
                            </div>
                            <div className="form-group col-md-12">
                                <label htmlFor="description"> Description </label>
                                <input type="text" id="description" onChange={(e) => this.handleInputChanges(e)} name="description" className="form-control" placeholder="Enter Description" />
                            </div>
                            <div className="form-group col-md-4 pull-right">
                                <button className="btn btn-success" type="submit">
                                    Create Customer
                                </button>
                                {loading &&
                                    <span className="fa fa-circle-o-notch fa-spin" />
                                }
                            </div>
                        </form>
                    </div>
                </div>
            )
        }
      ...
      

      Here, you created a form with the input fields to hold the values of the first_name, last_name, email, phone, address, and description of a customer. Each of the input fields have a method handleInputChanges() that runs on every keystroke, updating the React state with the value it obtains from the input field. Furthermore, depending on the state of the application, a boolean variable named submitSuccess will control the message that the application will display before and after creating a new customer.

      You can see the complete code for this file in this GitHub repository.

      Save and exit Create.tsx.

      Now that you have added the appropriate logic to the Create component file for the application, you'll proceed to add contents for the Edit component file.

      Open your Edit.tsx file within the customer folder, and start by adding the following content to import React, axios, and also define TypeScript interfaces:

      /src/components/customer/Edit.tsx

      import * as React from 'react';
      import { RouteComponentProps, withRouter } from 'react-router-dom';
      import axios from 'axios';
      
      export interface IValues {
          [key: string]: any;
      }
      export interface IFormState {
          id: number,
          customer: any;
          values: IValues[];
          submitSuccess: boolean;
          loading: boolean;
      }
      

      Similarly to the Create component, you import the required modules and create IValues and IFormState interfaces respectively. The IValues interface defines the data type for the input fields' values, while you'll use IFormState to declare the expected type for the state object of the application.

      Next, create the EditCustomer class component directly after the IFormState interface block as shown here:

      /src/components/customer/Edit.tsx

      ...
      class EditCustomer extends React.Component<RouteComponentProps<any>, IFormState> {
          constructor(props: RouteComponentProps) {
              super(props);
              this.state = {
                  id: this.props.match.params.id,
                  customer: {},
                  values: [],
                  loading: false,
                  submitSuccess: false,
              }
          }
      }
      export default withRouter(EditCustomer)
      

      This component takes the RouteComponentProps<any> and an interface of IFormState as a parameter. You use the addition of <any> to the RouteComponentProps because whenever React Router parses path parameters, it doesn’t do any type conversion to ascertain whether the type of the data is number or string. Since you're expecting a parameter for uniqueId of a customer, it is safer to use any.

      Now add the following methods within the component:

      /src/components/customer/Edit.tsx

      ...
          public componentDidMount(): void {
              axios.get(`http://localhost:5000/customers/${this.state.id}`).then(data => {
                  this.setState({ customer: data.data });
              })
          }
      
          private processFormSubmission = async (e: React.FormEvent<HTMLFormElement>): Promise<void> => {
              e.preventDefault();
              this.setState({ loading: true });
              axios.patch(`http://localhost:5000/customers/${this.state.id}`, this.state.values).then(data => {
                  this.setState({ submitSuccess: true, loading: false })
                  setTimeout(() => {
                      this.props.history.push('/');
                  }, 1500)
              })
          }
      
          private setValues = (values: IValues) => {
              this.setState({ values: { ...this.state.values, ...values } });
          }
          private handleInputChanges = (e: React.FormEvent<HTMLInputElement>) => {
              e.preventDefault();
              this.setValues({ [e.currentTarget.id]: e.currentTarget.value })
          }
      ...
      }
      
      export default withRouter(EditCustomer)
      

      First, you add a componentDidMount() method, which is a lifecycle method that is being called when the component is created. The method takes the id obtained from the route parameter to identify a particular customer as a parameter, uses it to retrieve their details from the database and then populates the form with it. Furthermore, you add methods to process form submission and handle changes made to the values of the input fields.

      Lastly, add the render() method for the Edit component:

      /src/components/customer/Edit.tsx

      ...
          public render() {
              const { submitSuccess, loading } = this.state;
              return (
                  <div className="App">
                      {this.state.customer &&
                          <div>
                              < h1 > Customer List Management App</h1>
                              <p> Built with React.js and TypeScript </p>
      
                              <div>
                                  <div className={"col-md-12 form-wrapper"}>
                                      <h2> Edit Customer </h2>
                                      {submitSuccess && (
                                          <div className="alert alert-info" role="alert">
                                              Customer's details has been edited successfully </div>
                                      )}
                                      <form id={"create-post-form"} onSubmit={this.processFormSubmission} noValidate={true}>
                                          <div className="form-group col-md-12">
                                              <label htmlFor="first_name"> First Name </label>
                                              <input type="text" id="first_name" defaultValue={this.state.customer.first_name} onChange={(e) => this.handleInputChanges(e)} name="first_name" className="form-control" placeholder="Enter customer's first name" />
                                          </div>
                                          <div className="form-group col-md-12">
                                              <label htmlFor="last_name"> Last Name </label>
                                              <input type="text" id="last_name" defaultValue={this.state.customer.last_name} onChange={(e) => this.handleInputChanges(e)} name="last_name" className="form-control" placeholder="Enter customer's last name" />
                                          </div>
                                          <div className="form-group col-md-12">
                                              <label htmlFor="email"> Email </label>
                                              <input type="email" id="email" defaultValue={this.state.customer.email} onChange={(e) => this.handleInputChanges(e)} name="email" className="form-control" placeholder="Enter customer's email address" />
                                          </div>
                                          <div className="form-group col-md-12">
                                              <label htmlFor="phone"> Phone </label>
                                              <input type="text" id="phone" defaultValue={this.state.customer.phone} onChange={(e) => this.handleInputChanges(e)} name="phone" className="form-control" placeholder="Enter customer's phone number" />
                                          </div>
                                          <div className="form-group col-md-12">
                                              <label htmlFor="address"> Address </label>
                                              <input type="text" id="address" defaultValue={this.state.customer.address} onChange={(e) => this.handleInputChanges(e)} name="address" className="form-control" placeholder="Enter customer's address" />
                                          </div>
                                          <div className="form-group col-md-12">
                                              <label htmlFor="description"> Description </label>
                                              <input type="text" id="description" defaultValue={this.state.customer.description} onChange={(e) => this.handleInputChanges(e)} name="description" className="form-control" placeholder="Enter Description" />
                                          </div>
                                          <div className="form-group col-md-4 pull-right">
                                              <button className="btn btn-success" type="submit">
                                                  Edit Customer </button>
                                              {loading &&
                                                  <span className="fa fa-circle-o-notch fa-spin" />
                                              }
                                          </div>
                                      </form>
                                  </div>
                              </div>
                          </div>
                      }
                  </div>
              )
          }
      ...    
      

      Here, you created a form to edit the details of a particular customer, and then populated the input fields within that form with the customer's details that your application's state obtained. Similarly to the Create component, changes made to all the input fields will be handled by the handleInputChanges() method.

      You can see the complete code for this file in this GitHub repository.

      Save and exit Edit.tsx.

      To view the complete list of customers created within the application, you’ll create a new component within the ./src/components folder and name it Home.tsx:

      • cd ./src/components
      • nano Home.tsx

      Add the following content:

      /src/components/Home.tsx

      import * as React from 'react';
      import { Link, RouteComponentProps } from 'react-router-dom';
      import axios from 'axios';
      
      interface IState {
          customers: any[];
      }
      
      export default class Home extends React.Component<RouteComponentProps, IState> {
          constructor(props: RouteComponentProps) {
              super(props);
              this.state = { customers: [] }
          }
          public componentDidMount(): void {
              axios.get(`http://localhost:5000/customers`).then(data => {
                  this.setState({ customers: data.data })
              })
          }
          public deleteCustomer(id: number) {
              axios.delete(`http://localhost:5000/customers/${id}`).then(data => {
                  const index = this.state.customers.findIndex(customer => customer.id === id);
                  this.state.customers.splice(index, 1);
                  this.props.history.push('/');
              })
          }
      }
      

      Here, you've imported React, axios, and other required components from React Router. You created two new methods within the Home component:

      • componentDidMount(): The application invokes this method immediately after a component is mounted. Its responsibility here is to retrieve the list of customers and update the home page with it.
      • deleteCustomer(): This method will accept an id as a parameter and will delete the details of the customer identified with that id from the database.

      Now add the render() method to display the table that holds the list of customers for the Home component:

      /src/components/Home.tsx

      ...
      public render() {
              const customers = this.state.customers;
              return (
                  <div>
                      {customers.length === 0 && (
                          <div className="text-center">
                              <h2>No customer found at the moment</h2>
                          </div>
                      )}
                      <div className="container">
                          <div className="row">
                              <table className="table table-bordered">
                                  <thead className="thead-light">
                                      <tr>
                                          <th scope="col">Firstname</th>
                                          <th scope="col">Lastname</th>
                                          <th scope="col">Email</th>
                                          <th scope="col">Phone</th>
                                          <th scope="col">Address</th>
                                          <th scope="col">Description</th>
                                          <th scope="col">Actions</th>
                                      </tr>
                                  </thead>
                                  <tbody>
                                      {customers && customers.map(customer =>
                                          <tr key={customer.id}>
                                              <td>{customer.first_name}</td>
                                              <td>{customer.last_name}</td>
                                              <td>{customer.email}</td>
                                              <td>{customer.phone}</td>
                                              <td>{customer.address}</td>
                                              <td>{customer.description}</td>
                                              <td>
                                                  <div className="d-flex justify-content-between align-items-center">
                                                      <div className="btn-group" style={{ marginBottom: "20px" }}>
                                                          <Link to={`edit/${customer.id}`} className="btn btn-sm btn-outline-secondary">Edit Customer </Link>
                                                          <button className="btn btn-sm btn-outline-secondary" onClick={() => this.deleteCustomer(customer.id)}>Delete Customer</button>
                                                      </div>
                                                  </div>
                                              </td>
                                          </tr>
                                      )}
                                  </tbody>
                              </table>
                          </div>
                      </div>
                  </div>
              )
          }
      ...
      

      In this code block, you retrieve the lists of customers from the application's state as an array, iterate over it, and display it within an HTML table. You also add the customer.id parameter, which the method uses to identify and delete the details of a particular customer from the list.

      Save and exit Home.tsx.

      You've adopted a statically typed principle for all the components created with this application by defining types for the components and props through the use of interfaces. This is one of the best approaches to using TypeScript for a React application.

      With this, you've finished creating all the required reusable components for the application. You can now update the app component with links to all the components that you have created so far.

      Step 4 — Setting Up Routing and Updating the Entry Point of the Application

      In this step, you will import the necessary components from the React Router package and configure the App component to render different components depending on the route that is loaded. This will allow you to navigate through different pages of the application. Once a user visits a route, for example /create, React Router will use the path specified to render the contents and logic within the appropriate component defined to handle such route.

      Navigate to ./src/App.tsx:

      Then replace its content with the following:

      /src/App.tsx

      import * as React from 'react';
      import './App.css';
      import { Switch, Route, withRouter, RouteComponentProps, Link } from 'react-router-dom';
      import Home from './components/Home';
      import Create from './components/customer/Create';
      import EditCustomer from './components/customer/Edit';
      
      class App extends React.Component<RouteComponentProps<any>> {
        public render() {
          return (
            <div>
              <nav>
                <ul>
                  <li>
                    <Link to={'/'}> Home </Link>
                  </li>
                  <li>
                    <Link to={'/create'}> Create Customer </Link>
                  </li>
                </ul>
              </nav>
              <Switch>
                <Route path={'/'} exact component={Home} />
                <Route path={'/create'} exact component={Create} />
                <Route path={'/edit/:id'} exact component={EditCustomer} />
              </Switch>
            </div>
          );
        }
      }
      export default withRouter(App);
      

      You imported all the necessary components from the React Router package and you also imported the reusable components for creating, editing, and viewing customers' details.

      Save and exit App.tsx.

      The ./src/index.tsx file is the entry point for this application and renders the application. Open this file and import React Router into it, then wrap the App component inside a BrowserRouter:

      /src/index.tsx

      import React from 'react';
      import ReactDOM from 'react-dom';
      import './index.css';
      import App from './App';
      import { BrowserRouter } from 'react-router-dom'; 
      import * as serviceWorker from './serviceWorker';
      ReactDOM.render(
          <BrowserRouter>
              <App />
          </BrowserRouter>
          , document.getElementById('root')
      );
      serviceWorker.unregister();
      

      React Router uses the BrowserRouter component to make your application aware of the navigation, such as history and current path.

      Once you've finished editing Index.tsx, save and exit.

      Lastly, you will use Bootstrap to add some style to your application. Bootstrap is a popular HTML, CSS, and JavaScript framework for developing responsive, mobile-first projects on the web. It allows developers to build an appealing user interface without having to write too much CSS. It comes with a responsive grid system that gives a web page a finished look that works on all devices.

      To include Bootstrap and styling for your application, replace the contents of ./src/App.css with the following:

      /src/App.css

      @import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';
      
      .form-wrapper {
        width: 500px;
        margin: 0 auto;
      }
      .App {
        text-align: center;
        margin-top: 30px;
      }
      nav {
        width: 300px;
        margin: 0 auto;
        background: #282c34;
        height: 70px;
        line-height: 70px;
      }
      nav ul li {
        display: inline;
        list-style-type: none;
        text-align: center;
        padding: 30px;
      }
      nav ul li a {
        margin: 50px 0;
        font-weight: bold;
        color: white;
        text-decoration: none;
      }
      nav ul li a:hover {
        color: white;
        text-decoration: none;
      }
      table {
        margin-top: 50px;
      }
      .App-link {
        color: #61dafb;
      }
      @keyframes App-logo-spin {
        from {
          transform: rotate(0deg);
        }
        to {
          transform: rotate(360deg);
        }
      }
      

      You have used Bootstrap here to enhance the look and feel of the application by giving it a default layout, styles, and color. You have also added some custom styles, particularly to the navigation bar.

      Save and exit App.css.

      In this section, you have configured React Router to render the appropriate component depending on the route visited by the user and also added some styling to make the application more attractive to users. Next, you will test all the functionality implemented for the application.

      Step 5 — Running Your Application

      Now that you have set up the frontend of this application with React and TypeScript by creating several reusable components, and also built a REST API with the json-server, you can run your app.

      Navigate back to the project’s root folder:

      • cd ~/typescript-react-app

      Next run the following command to start your app:

      Note: Make sure your server is still running in the other terminal window. Otherwise, start it with: yarn server.

      Navigate to http://localhost:3000 to view the application from your browser. Then proceed to click on the Create button and fill in the details of a customer.

      Create customer page

      After entering the appropriate values in the input fields, click on the Create Customer button to submit the form. The application will redirect you back to your homepage once you're done creating a new customer.

      View customers page

      Click the Edit Customer button for any of the rows and you will be directed to the page that hosts the editing functionality for the corresponding customer on that row.

      Edit customer page

      Edit the details of the customer and then click on Edit Customer to update the customer’s details.

      You've run your application to ensure all the components are working. Using the different pages of your application, you've created and edited a customer entry.

      Conclusion

      In this tutorial you built a customer list management app with React and TypeScript. The process in this tutorial is a deviation from using JavaScript as the conventional way of structuring and building applications with React. You've leveraged the benefits of using TypeScript to complete this front-end focused tutorial.

      To continue to develop this project, you can move your mock back-end server to a production-ready back-end technology like Express or Nest.js. Furthermore, you can extend what you have built in this tutorial by adding more features such as authentication and authorization with different tools like the Passport.js authentication library.

      You can find the complete source code for the project on GitHub.



      Source link

      Building Your Own Business Website? Don’t Make These 10 Mistakes


      It can be daunting to get a business website up and running.

      Let’s be real here: if you weren’t a little bit jittery about it, we’d be worried. Not because you can’t do this. You totally can. It’s easy to build a great-looking business website if you use the right tools — and you don’t even have to know how to code!

      No, it’s daunting because your website matters so much to the health of your business. It’ll help you generate leads, drive conversions, and build your brand. But like a first date, there are a lot of ways to screw this thing up.

      “So, you’re paying, right?”

      “I’m a huge Nickleback fan.”

      “Do you mind if my mom joins us?”

      Luckily, avoiding “website don’ts” is much easier than finding love in a hopeless place. In this post, I’ll outline the 10 biggest mistakes you could make when setting up a website for your small business. Avoid these pitfalls and you’ll be on your way to turning visitors into devoted customers. Ah, l’amour.

      1. Failing To Make A Responsive Website

      This is the ultimate beginner’s mistake. So what is a responsive website anyway?

      Simply put, it’s a website that responds to its environment to give the user the best possible viewing experience. In other words, if a user comes searching for your website on a mobile phone, then the site’s layout will display in a different, more accessible way than if they were visiting the site on a desktop.

      We’ve gone in-depth on why mobile-friendly website design matters here on the blog before. But here are the simple facts: 61 percent of users who have trouble accessing a mobile site are unlikely to return. Of those, 40 percent will seek out a competitor’s site instead. And if you don’t create a mobile-friendly website, Google’s going to ding you too.

      The takeaway?

      When choosing a website builder or platform to create your website, make sure you pick one that offers responsive designs. You don’t want to mess around with a stagnant design that will drive away mobile visitors.

      2. Not Customizing Your Theme

      One of the best things about using a content management system is the free themes available at your fingertips. In fact, as soon as you settle on your web hosting company and purchase a domain, you can select the perfect theme to match your brand in mere minutes.

      However, it’s important to remember whatever platform you use, you’re going to have to customize it to match your brand’s style. Otherwise, you’ll be left with a website that looks exactly like thousands of other business sites on the web — a big mistake.

      Happily, with Remixer, our in-house website builder, it’s easy to personalize your site. You can upload and insert your own images (or use our royalty-free gallery, your call), flesh out your unique content, and place menu items where you need them to build your dream website.

      3. Using Jargon

      We get it. You have been working in your field for years and years, and you’re literally a master of your industry. You know what “IPC,” “VC Money,” and “apportunity” stand for, but I’ve got news for you — your website visitors don’t.

      If a visitor lands on your website and the copywriting is full of technical jargon they can’t understand, they’re not going to stick around to parse through your metaphors.

      Remember: the average human has a shorter attention span than a goldfish. That’s a piddly eight seconds. This means when customers find your site, they need to encounter copy that is straightforward and encourages them to take action fast — whether that’s watching a video, entering your sign-up flow, or subscribing to an email newsletter.

      If you need a good example, Dropbox Business slays when it comes to website design and simple copywriting. Let’s take a look at their homepage.

      dropbox business home page

      What is Dropbox Business doing right?

      • The headline is straightforward with no jargon.
      • The subheading tells you what they do in one easy-to-follow sentence. In fact, it’s immediately clear what the company offers.
      • The call-to-action is easy to see (and click)!

      When approaching copywriting and design, be like Dropbox.

      4. Not Thinking About Readability

      Not only does your copywriting need to be sweet and simple, but the design also has to be easy on the eyes.

      And I don’t just mean nice to look at; it also has to be easy to read.

      When you use a website builder, you have free reign to customize your website as you wish, but this doesn’t mean you should part with best practices. To make sure your users don’t get turned off by your design, stick to these rules:

      • Keep Your Font Sizes Consistent — Larger font sizes are a good way to say, “This is important, so pay attention.” Smaller font sizes should be used for more in-depth information. When building your website, don’t go hog wild and use a bunch of different sizes. Stick to three or four sizes.
      • Consider Your Fonts — Papyrus may look cute on your kid’s 5th birthday party invite, but it doesn’t look great on your website. Luckily, most website builders themes will only use fonts that designers have already vetted for readability and looks. One important tip: Sans-serif fonts — the ones without the extra little flourishes — are generally easier to read on the web.
      • Choose Contrasting Colors — When selecting a color palette for your website, make sure the background images don’t drown out your font. Readability has to be the first priority. If you’re design challenged (no shame in admitting that, by the way), Remixer comes with preset color mixes so you don’t have to worry about the subtle differences between Seafoam and Aqua.

      freshbooks cloud accounting home page

      So who is doing readability right? FreshBooks is nailing it.

      • The copy is free of jargon, simple, and straight to the point.
      • Even though their content is more robust than the Dropbox example above, it’s still easy to understand.
      • The colors work nicely with each other, and none of the images detract from the text.
      • The most important messages are in larger font while the supplemental information is in a smaller font.

      Overall, the readability of this website is on the money — which is good because, well, their business is all about the dollars.

      5. Falling For Search Engine Optimization Myths

      Every new business owner hopes to create a website that will sit on the top of the search results on Google, Bing, Yahoo, and every other search engine. And they hope to rank for more than just one keyword.

      However, the truth of the matter is that a good SEO strategy takes time, smarts, and money. Plus, it’s impossible to successfully optimize your homepage for hundreds of keywords. That’s just not how the internet works, and if you try to cut corners, Google knows where you live.

      Seriously, it knows.

      A better strategy is to think about the top keyword for your website and optimize your content to rank for that keyword. Here are a few suggestions:

      • Write Long-Form Content — Once upon a time, stuffing your content with your top keyword would help you rank in the search results. Gone are those days, and just like on that first date we talked about earlier, you’ll actually be penalized for trying too hard. These days, it’s better to simply write your content for the user. Be as comprehensive and helpful as possible and Google will reward you.
      • Structure Your Content with Heading Tags — Heading tags — the top-down <h1> to <h6>s — are often seen as a “meh, not that important” sort of thing, but they really do matter. Headings give structure to your pages, making it easier for both readers and Google bots to consume your content. To get the most SEO bang for your buck with headings, follow this guide from Yoast.
      • Add a Call-to-Action — Your homepage should have a clear call-to-action (CTA). Not only will it help direct your readers to do the thing you want them to do — buy your product, sign up for your service, or subscribe to your newsletter — but it will help Google focus on what is important to you.

      The Moz blog is a solid example of on-point optimization. Here’s what they’re doing right:

      • Clear, strong heading tags in every post.
      • Structured content that is easy to follow, read, and scan.
      • The posts aren’t laden with annoying keywords. Instead, it supports the H1 tag and is helpful to readers.

      6. Going Pop-Up Crazy

      Here’s how I like to think about pop-ups. When someone puts a sign in front of your face, it’s difficult not to pay attention to it. But when someone puts a whole bunch of signs in your face, it’s impossible to pay attention to any of them.

      Helpful pop-ups that serve your readers are a great way to build your business. For example, you can include ONE pop-up asking someone to do ONE of the following: join your mailing list, share a post, follow you on social media, or sign up for an upcoming event.

      But the second you start throwing pop-ups on your website to join your mailing list and share a post and follow you on social media and sign up for your webinar, and . . . you are not serving your visitors — or your business.

      When it comes to pop-ups, be wise. Determine what the most pressing action you want your users to take is and then build a pop-up around that action. Leave the rest out. Simple as that.

      example of pop-up 'super early bird 65% off'

      Digital Marketer, one of the marketing world’s top thought leaders, serves as a great example of using pop-ups wisely.

      • Digital Marketer is an online publication with thousands of daily followers. They use this pop-up to let subscribers know about an upcoming event.
      • Once a subscriber either enters their information or opts out, the pop-up disappears.
      • The pop-up isn’t asking for multiple actions from the subscriber.

      Feel free to use a pop-up on your website. Just don’t go crazy or your website visitors will feel like they’ve shown up at a protest with mixed messages.

      Be Awesome on the Internet

      Join our monthly newsletter for tips and tricks to build your dream website!

      7. Slow Server Times

      Did you know customers will only wait 4 seconds for a site to load before clicking out of the website, according to a study by Akamai Technologies? That means if you want to keep your customers interested, you need to make sure your site loads whip fast.

      The good news is when you build your site with Remixer, you are working with a product that is configured to make load times faster. Remixer’s static pages load whip-fast compared to dynamic ones.

      8. Poor Navigation

      The internet yields nearly 7 billion global searches a day, and websites with intuitive navigation are rewarded with more visitors (and visitors who stick around for longer). If you can’t help your users get what they want immediately, chances are they will move on to a competitor’s site.

      Even if you’re not a professional, there are a few simple things you can do to make sure your design is intuitive for visitors:

      • Use a Theme — The easiest way to create a winning website is to use a website builder. With Remixer, the important structural elements you’ll need for a basic website are incorporated into each of our expert-built themes. That means, all you have to do is choose a design that works with your brand, add your content, and boom, you’ve got a well-designed website — no coding required.
      • Stick to the Standard — Humans are creatures of habit. And most of us are trained to expect vertical navigation on the left side of the page and horizontal navigation across the top of the page. To avoid confusion, keep your navigation standard.
      • Don’t Overwhelm Users — You may be tempted to include several links in your navigation bar. But remember: less is more. Stick to the basics — About, Products, Services, Contact, etc. — in your navigation menu.

      You know what’s coming next, don’t you? A good example! 4 Rivers Smokehouse has a really sleek design.

      • The navigation bar is up top, simple, and easy to read.
      • You know exactly how to take action as soon as you view the home page. “Show me the menu!”
      • The design is simple — and makes you want to dive into a plate of slow-roasted brisket.

      9. Outdated Information and/or Design

      I know we just talked about brisket, but building a website is not like making slow-cooked pork. You can’t set it and forget it! Your website requires regular updates and maintenance for a variety of reasons.

      • Updated Information Helps Customers — If you let your website information get outdated, it will be difficult for customers to find you, order from you, and remain a loyal customer. Don’t leave them hanging!
      • It Keeps Google Happy — Google ranks websites based on a huge algorithm. One major driver of rankings: how fresh and robust is your site’s content? This means you need to frequently add new content to your site (blog posts, anyone?) and routinely spruce up your older pages and posts.
      • Updated Design Keeps Your Brand Relevant — The tech world is constantly innovating, and you need to stay in the game when it comes to design trends and best practices. For example, here’s how Google and Facebook, two of the world’s most popular websites, looked when they first launched. Imagine how successful they would have been if they never updated their look and feel. Yeah, it’s not a pretty picture.
      Google home page in 1996
      Google in 1996
      Facebook in 2004
      Facebook in 2004

      As you continue to build (and grow!) your business, make sure your website keeps up.

      10. Don’t Go It Alone

      Building a website from scratch is a lofty goal, but unless you’re really looking forward to investing in the process, it can be a big drain on your resources. And remember, your time counts as a resource when you’re bootstrapping a small business. If you need a responsive, professional-looking website — and you need it fast — Remixer is the tool for you.

      Need a Beautiful Website?

      Design it yourself with Remixer, our easy-to-use website builder. No coding required.

      You can start with a free responsive theme that’s been put together by our web experts to help you sidestep all the mistakes we’ve outlined above. Our themes are designed to load quickly, look great, and help you easily plug in SEO-friendly content.

      All you have to do is import your content, customize your theme, and then hit ‘publish.’ And if you get stuck somewhere along the way, the DreamHost team is just a chat away. Today is the day to start building your own Remixer site for free.



      Source link

      INAP Introduces New Managed AWS Support Plans


      INAP announced today its new Managed AWS support plans, offering greater service capabilities and more flexibility for a broad range of public cloud use cases and budgets. Each plan offers critical features and benefits like consolidated billing, access to certified AWS architects and technicians, and around-the-clock troubleshooting.

      Premium features include advanced deployment services, interconnectivity to AWS from INAP data centers, flexible solution architecture, and comprehensive reporting and cost optimization consultation.

      You can learn all the key details of the support plans—Service First On-Demand and Service First Premier—by reading on below or heading to our Managed AWS service page.

      First, though, some context for why we believe Managed AWS with INAP is a whole lot more than a one-off solution.

      INAP Managed AWS Certified Architects

       

      Multicloud & Hybrid IT Have Arrived

      Managed AWS complements INAP’s existing cloud, colocation and network portfolio, allowing customers to fully realize the potential of hybrid strategies shaping the future of IT.

      As reported in INAP’s 2019 State of IT Infrastructure Management, on-premise-only IT strategies are facing steep decline. A majority (56 percent) of organizations currently maintaining their own data centers will be moving at least some of their infrastructure off-premise within the next three years; 78 percent of those organizations will be selecting hyperscale providers like AWS for specific workloads.

      The challenge for many organizations, however, is that AWS is whole new ball game from an operational and economics perspective.

      While the platform offers compelling solutions for a variety of applications, it is as complex as it is powerful. Even for skilled IT infrastructure professionals, achieving proficiency in the platform and its ever-growing list of tools and products is no easy feat. According to Amazon’s own recommendations, attempting the AWS Solutions Architect Associate certification requires a year of platform experience and studying. Practitioners chasing mastery can add another year for the Professional certificate and several months of prep for specialty certifications like networking and security.

      Do you need these credentials to spin up a cloud environment on AWS? No, but we believe there are two related reasons Amazon emphasizes their certification programs and maintains a vast database of technical documentation.

      First, AWS’s support model is designed for DIY shops. Outside of resolving underlying AWS infrastructure and network issues, Amazon leaves you on your own for environment configuration and optimization.

      Second, running mission-critical workloads in AWS without a deep understanding of the platform’s nuances and complexity can lead to significant problems: sticker shock and blown budgets, workload performance degradation, or worse yet, security vulnerabilities and downtime caused by environment misconfigurations and architectural mistakes.

      For many IT organizations operating hybrid and multicloud strategies, learning a brand-new platform is not the best use of time and limited resources.

      In fact, nearly 8 in 10 IT pros we surveyed believe they could bring more value to their organization if they spent less time on routine tasks like cloud server monitoring and maintenance. Increasingly, IT professionals’ skills are better spent on value-added tasks like new application development and collaborating with business units on new technology initiatives.

      This is all to say that Amazon has made a conscious choice to rely on third-party partners like INAP to help customers succeed.

      Our Managed AWS plans are carefully designed to help IT organizations achieve the promise of hyperscale cloud without confronting operational headaches along the way.

      Simply put: Our experienced team of AWS certified solutions architects and support experts mastered AWS so you don’t have to.

      INAP Managed AWS: Service Plan Overview

      Managed Support Services

      Service First On-Demand

      For a low monthly fee, customers receive core infrastructure monitoring and response, ticketing and hotline access, consolidated billing and basic issue mitigation—e.g., break/fix and simple configurations.

      Service First Premier

      A fully managed, proactive support experience with advanced monitoring, performance optimization best practices, and detailed monthly reporting. You’ll receive hands-on management for all supported AWS services active in your deployment. For infrastructure issues with AWS data centers, our team will work directly with Amazon representatives.


      CHAT NOW

      AWS Migration Support and Deployment Services

      For customers new to AWS or for customers deploying new environments, INAP offers two tiers of onboarding and deployment services.

      Tier 1: A certified onboarding engineer will implement architecture best-practices tailored to your applications, spin-up your instances and configure services.

      Tier 2: This white-glove onboarding service includes everything from Tier 1, plus:

      • Custom image configuration
      • Network and load balancer configuration
      • Access management and security configuration
      • Set up of up to five enhanced AWS services

      Add-on services include advanced solution architecture for complex deployments, migration support and AWS Direct Connect configuration.

      Deployment services are only available to customers signing up for one of INAP’s Service First support plans.

      Common AWS Use Cases

      INAP’s AWS experts support a vast array of Amazon’s powerful toolkit, specializing in four primary areas: hyperscale compute and storage environments, off-premise backup, serverless, and multicloud.

      Hyperscale: INAP manages and optimizes your core AWS infrastructure, including EC2, VPC, ELB, S3 and RDS.   

      Off-Premise Backup: Using AWS’s wide range of cloud backup storage services to support both application and archival compliance requirements, INAP manages the backup schedule and data life cycle.

      Serverless: Using AWS Lamda, INAP will design and operate the ideal environment for your serverless backend and data processing systems.

      Multicloud & Hybrid: Pair the ideal AWS solution with your on-premise, INAP Colo or INAP Cloud environment to improve performance and reliability.

      In the coming weeks, we’ll break down common reference architectures for each of these specialty areas and share advice for getting started.

      In the meantime, chat with us today and download the following resources:

      INAP Managed AWS Overview [pdf]
      INAP Managed AWS FAQ [pdf]   

      Interested in learning more?

      CHAT NOW

      Jennifer Curry
      • SVP, Global Cloud Services


      Jennifer Curry is SVP, Global Cloud Services. She is an operational and technology leader with over 17 years of experience in the IT industry, including seven years in the hosting/cloud market. READ MORE



      Source link