In this tutorial, I will show you how to build a React Typescript with Rest API call example using Hooks and Axios, display and modify data with Router & Bootstrap.
Related Posts:
– React Custom Hook in Typescript example
– React Typescript File Upload example
– React Table example: CRUD App | react-table 7
– React Hook Form Typescript example with Validation
– React Typescript (Components) example Project with Axios and Web API
Security:
– React Hooks: JWT Authentication (without Redux) example
– React Hooks + Redux: JWT Authentication example
Serverless with Firebase:
– React Hooks + Firebase Realtime Database: CRUD App
– React Hooks + Firestore example: CRUD app
Contents
- Overview of React Typescript with API call example
- React Typescript App Diagram with Axios and Router
- Technology
- React Typescript Project structure
- Setup React Typescript with API call Project
- Install Bootstrap for React Typescript Project
- Add React Router to React Typescript Project
- Add Navbar to React Typescript Project
- Define Data Type
- Initialize Axios for React Typescript API call example
- Create Data Service
- Create React Typescript with API call Components
- Add CSS style for React Typescript Components
- Configure Port for React Typescript Client with API call
- Run React Typescript App
- Conclusion
- Further Reading
- Source Code
Overview of React Typescript with API call example
We will build a React Hooks Typescript Tutorial Application in that:
- Each Tutorial has id, title, description, published status.
- We can create, retrieve, update, delete Tutorials.
- There is a Search bar for finding Tutorials by title.
Here are screenshots of our React Typescript CRUD Application.
– Create a Tutorial:
– Retrieve all items:
– Click on Edit button to update an item:
On this Page, you can:
- change status to Published using Publish button
- delete the item using Delete button
- update the item details with Update button
If you need Form Validation with React Hook Form 7, please visit:
React Hook Form Typescript example with Validation
– Search Tutorials by title:
This React Typescript Client consumes the following Web API:
Methods | Urls | Actions |
---|---|---|
POST | /api/tutorials | create new Tutorial |
GET | /api/tutorials | retrieve all Tutorials |
GET | /api/tutorials/:id | retrieve a Tutorial by :id |
PUT | /api/tutorials/:id | update a Tutorial by :id |
DELETE | /api/tutorials/:id | delete a Tutorial by :id |
DELETE | /api/tutorials | delete all Tutorials |
GET | /api/tutorials?title=[keyword] | find all Tutorials which title contains keyword |
You can find step by step to build a Server like this in one of these posts:
– Express, Sequelize & MySQL
– Express, Sequelize & PostgreSQL
– Express, Sequelize & SQL Server
– Express & MongoDb
– Spring Boot & MySQL
– Spring Boot & PostgreSQL
– Spring Boot & MongoDB
– Spring Boot & SQL Server
– Spring Boot & H2
– Spring Boot & Cassandra
– Spring Boot & Oracle
– Django & MySQL
– Django & PostgreSQL
– Django & MongoDB
If you want to work with table like this:
Please visit: React Table example: CRUD App | react-table 7
React Typescript App Diagram with Axios and Router
Let’s see the React Application Diagram that we’re gonna implement:
– The App
component is a container with React Router
. It has navbar
that links to routes paths.
– TutorialsList
gets and displays Tutorials.
– Tutorial
has form for editing Tutorial’s details based on :id
.
– AddTutorial
has form for submission new Tutorial.
– They call TutorialDataService
functions which use axios
to make HTTP requests and receive responses.
If you want to work with Redux like this:
Please visit: React Hooks + Redux: CRUD example with Axios and Rest API
Technology
- React 17/16
- typescript 4.3.5
- react-router-dom 6
- axios 0.26.1
- bootstrap 4.6.0
React Typescript Project structure
Now look at the project directory structure:
Let me explain it briefly.
– package.json contains 5 main modules: react
, typescript
, react-router-dom
, axios
& bootstrap
.
– App
is the container that has Router
& navbar.
– types/Tutorial.ts exports ITutorialData
interface.
– There are 3 components: TutorialsList
, Tutorial
, AddTutorial
.
– http-common.ts initializes axios with HTTP base Url and headers.
– TutorialService
has methods for sending HTTP requests to the Apis.
– .env configures port for this React CRUD App.
Setup React Typescript with API call Project
Open cmd at the folder you want to save Project folder, run command:
npx create-react-app react-typescript-api-call --template typescript
After the process is done. We create additional folders and files like the following tree:
public
src
components
AddTutorial.tsx
Tutorial.tsx
TutorialsList.tsx
services
TutorialService.ts
types
Tutorial.ts
App.css
App.tsx
index.tsx
package.json
Install Bootstrap for React Typescript Project
Run command: npm install [email protected]
.
Open src/App.tsx and modify the code inside it as following-
import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
function App() {
return (
// ...
);
}
export default App;
Add React Router to React Typescript Project
When using Typescript with React.js, we don’t use Proptypes. Typescript is stronger than Propstypes.
– Run the command: npm install react-router-dom
.
– Open src/index.tsx and wrap App
component by BrowserRouter
object.
import ReactDOM from 'react-dom';
import { BrowserRouter } from "react-router-dom";
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
reportWebVitals();
Open src/App.tsx, this App
component is the root container for our application, it will contain a navbar
, and also, a Switch
object with several Route
. Each Route
points to a React Component.
import React from "react";
import { Routes, Route, Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import AddTutorial from "./components/AddTutorial";
import Tutorial from "./components/Tutorial";
import TutorialsList from "./components/TutorialsList";
const App: React.FC = () => {
return (
<div>
<nav className="navbar navbar-expand navbar-dark bg-dark">
<a href="/tutorials" className="navbar-brand">
bezKoder
</a>
<div className="navbar-nav mr-auto">
<li className="nav-item">
<Link to={"/tutorials"} className="nav-link">
Tutorials
</Link>
</li>
<li className="nav-item">
<Link to={"/add"} className="nav-link">
Add
</Link>
</li>
</div>
</nav>
<div className="container mt-3">
<Routes>
<Route path="/" element={<TutorialsList/>} />
<Route path="/tutorials" element={<TutorialsList/>} />
<Route path="/add" element={<AddTutorial/>} />
<Route path="/tutorials/:id" element={<Tutorial/>} />
</Routes>
</div>
</div>
);
}
export default App;
Define Data Type
Now we need to define the data type for Tutorial
. Create and export ITutorialData
interface in types/Tutorial.ts.
export default interface ITutorialData {
id?: any | null,
title: string,
description: string,
published?: boolean,
}
Initialize Axios for React Typescript API call example
Let’s install axios with command: npm install axios
.
Under src folder, we create http-common.ts file with following code:
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8080/api",
headers: {
"Content-type": "application/json"
}
});
You can change the baseURL
that depends on REST APIs url that your Server configures.
For more details about ways to use Axios, please visit:
Axios request: Get/Post/Put/Delete example
Create Data Service
In this step, we’re gonna create a service that uses axios object above to send HTTP requests.
The service exports CRUD functions and finder method:
- CREATE:
create
- RETRIEVE:
getAll
,get
- UPDATE:
update
- DELETE:
remove
,removeAll
- FINDER:
findByTitle
services/TutorialService.ts
import http from "../http-common";
import ITutorialData from "../types/Tutorial";
const getAll = () => {
return http.get<Array<ITutorialData>>("/tutorials");
};
const get = (id: any) => {
return http.get<ITutorialData>(`/tutorials/${id}`);
};
const create = (data: ITutorialData) => {
return http.post<ITutorialData>("/tutorials", data);
};
const update = (id: any, data: ITutorialData) => {
return http.put<any>(`/tutorials/${id}`, data);
};
const remove = (id: any) => {
return http.delete<any>(`/tutorials/${id}`);
};
const removeAll = () => {
return http.delete<any>(`/tutorials`);
};
const findByTitle = (title: string) => {
return http.get<Array<ITutorialData>>(`/tutorials?title=${title}`);
};
const TutorialService = {
getAll,
get,
create,
update,
remove,
removeAll,
findByTitle,
};
export default TutorialService;
We call axios (imported as http) get
, post
, put
, delete
method corresponding to HTTP Requests: GET, POST, PUT, DELETE to make CRUD Operations.
You can simplify import statement with:
Absolute Import in React
Create React Typescript with API call Components
Now we’re gonna build 3 components corresponding to 3 Routes defined before.
Add Object
This component has a Form to submit new Tutorial with 2 fields: title
& description
.
components/AddTutorial.tsx
import React, { useState, ChangeEvent } from "react";
import TutorialDataService from "../services/TutorialService";
import ITutorialData from '../types/Tutorial';
const AddTutorial: React.FC = () => {
const initialTutorialState = {
id: null,
title: "",
description: "",
published: false
};
const [tutorial, setTutorial] = useState<ITutorialData>(initialTutorialState);
const [submitted, setSubmitted] = useState<boolean>(false);
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
setTutorial({ ...tutorial, [name]: value });
};
const saveTutorial = () => {
var data = {
title: tutorial.title,
description: tutorial.description
};
TutorialDataService.create(data)
.then((response: any) => {
setTutorial({
id: response.data.id,
title: response.data.title,
description: response.data.description,
published: response.data.published
});
setSubmitted(true);
console.log(response.data);
})
.catch((e: Error) => {
console.log(e);
});
};
const newTutorial = () => {
setTutorial(initialTutorialState);
setSubmitted(false);
};
return ( ... );
};
export default AddTutorial;
First, we define and set initial state: tutorial
& submitted
.
Next, we create handleInputChange()
function to track the values of the input and set that state for changes. We also have a function to get tutorial
state and send the POST request to the Web API. It calls TutorialDataService.create()
method.
For return
, we check the submitted
state, if it is true, we show Add button for creating new Tutorial again. Otherwise, a Form with Submit button will display.
const AddTutorial: React.FC = () => {
...
return (
<div className="submit-form">
{submitted ? (
<div>
<h4>You submitted successfully!</h4>
<button className="btn btn-success" onClick={newTutorial}>
Add
</button>
</div>
) : (
<div>
<div className="form-group">
<label htmlFor="title">Title</label>
<input
type="text"
className="form-control"
id="title"
required
value={tutorial.title}
onChange={handleInputChange}
name="title"
/>
</div>
<div className="form-group">
<label htmlFor="description">Description</label>
<input
type="text"
className="form-control"
id="description"
required
value={tutorial.description}
onChange={handleInputChange}
name="description"
/>
</div>
<button onClick={saveTutorial} className="btn btn-success">
Submit
</button>
</div>
)}
</div>
);
};
export default AddTutorial;
List of Objects Component
There will be:
- a search bar for finding Tutorials by title.
- a tutorials array displayed as a list on the left.
- a selected Tutorial which is shown on the right.
So we will have following state:
searchTitle
tutorials
currentTutorial
andcurrentIndex
We also need to use 3 TutorialDataService
functions:
getAll()
removeAll()
findByTitle()
We’re gonna use the Effect Hook: useEffect()
to fetch the data from the Web API. This Hook tells React that the component needs to do something after render or performing the DOM updates. In this effect, we perform data fetching from API.
components/TutorialsList.tsx
import React, { useState, useEffect, ChangeEvent } from "react";
import TutorialDataService from "../services/TutorialService";
import ITutorialData from '../types/Tutorial';
const TutorialsList: React.FC = () => {
const [tutorials, setTutorials] = useState<Array<ITutorialData>>([]);
const [currentTutorial, setCurrentTutorial] = useState<ITutorialData | null>(null);
const [currentIndex, setCurrentIndex] = useState<number>(-1);
const [searchTitle, setSearchTitle] = useState<string>("");
useEffect(() => {
retrieveTutorials();
}, []);
const onChangeSearchTitle = (e: ChangeEvent<HTMLInputElement>) => {
const searchTitle = e.target.value;
setSearchTitle(searchTitle);
};
const retrieveTutorials = () => {
TutorialDataService.getAll()
.then((response: any) => {
setTutorials(response.data);
console.log(response.data);
})
.catch((e: Error) => {
console.log(e);
});
};
const refreshList = () => {
retrieveTutorials();
setCurrentTutorial(null);
setCurrentIndex(-1);
};
const setActiveTutorial = (tutorial: ITutorialData, index: number) => {
setCurrentTutorial(tutorial);
setCurrentIndex(index);
};
const removeAllTutorials = () => {
TutorialDataService.removeAll()
.then((response: any) => {
console.log(response.data);
refreshList();
})
.catch((e: Error) => {
console.log(e);
});
};
const findByTitle = () => {
TutorialDataService.findByTitle(searchTitle)
.then((response: any) => {
setTutorials(response.data);
setCurrentTutorial(null);
setCurrentIndex(-1);
console.log(response.data);
})
.catch((e: Error) => {
console.log(e);
});
};
return ( ... )
};
export default TutorialsList;
Let’s continue to implement UI elements:
...
import { Link } from "react-router-dom";
const TutorialsList: React.FC = () => {
...
return (
<div className="list row">
<div className="col-md-8">
<div className="input-group mb-3">
<input
type="text"
className="form-control"
placeholder="Search by title"
value={searchTitle}
onChange={onChangeSearchTitle}
/>
<div className="input-group-append">
<button
className="btn btn-outline-secondary"
type="button"
onClick={findByTitle}
>
Search
</button>
</div>
</div>
</div>
<div className="col-md-6">
<h4>Tutorials List</h4>
<ul className="list-group">
{tutorials &&
tutorials.map((tutorial, index) => (
<li
className={
"list-group-item " + (index === currentIndex ? "active" : "")
}
onClick={() => setActiveTutorial(tutorial, index)}
key={index}
>
{tutorial.title}
</li>
))}
</ul>
<button
className="m-3 btn btn-sm btn-danger"
onClick={removeAllTutorials}
>
Remove All
</button>
</div>
<div className="col-md-6">
{currentTutorial ? (
<div>
<h4>Tutorial</h4>
<div>
<label>
<strong>Title:</strong>
</label>{" "}
{currentTutorial.title}
</div>
<div>
<label>
<strong>Description:</strong>
</label>{" "}
{currentTutorial.description}
</div>
<div>
<label>
<strong>Status:</strong>
</label>{" "}
{currentTutorial.published ? "Published" : "Pending"}
</div>
<Link
to={"/tutorials/" + currentTutorial.id}
className="badge badge-warning"
>
Edit
</Link>
</div>
) : (
<div>
<br />
<p>Please click on a Tutorial...</p>
</div>
)}
</div>
</div>
);
};
export default TutorialsList;
If you click on Edit button of any Tutorial, the app will direct you to Tutorial page.
We use React Router Link
for accessing that page with url: /tutorials/:id
.
You can add Pagination to this Page, just follow instruction in the post:
React Pagination using Hooks example
Object details Component
For getting data & update, delete the Tutorial, this component will use 3 TutorialDataService
functions:
get()
update()
remove()
We also use the Effect Hook useEffect()
to get Tutorial by id in the URL (with the help of useParams()
hook).
components/Tutorial.tsx
import React, { useState, useEffect, ChangeEvent } from "react";
import { useParams, useNavigate } from 'react-router-dom';
import TutorialDataService from "../services/TutorialService";
import ITutorialData from "../types/Tutorial";
const Tutorial: React.FC = () => {
const { id }= useParams();
let navigate = useNavigate();
const initialTutorialState = {
id: null,
title: "",
description: "",
published: false
};
const [currentTutorial, setCurrentTutorial] = useState<ITutorialData>(initialTutorialState);
const [message, setMessage] = useState<string>("");
const getTutorial = (id: string) => {
TutorialDataService.get(id)
.then((response: any) => {
setCurrentTutorial(response.data);
console.log(response.data);
})
.catch((e: Error) => {
console.log(e);
});
};
useEffect(() => {
if (id)
getTutorial(id);
}, [id]);
const handleInputChange = (event: ChangeEvent) => {
const { name, value } = event.target;
setCurrentTutorial({ ...currentTutorial, [name]: value });
};
const updatePublished = (status: boolean) => {
var data = {
id: currentTutorial.id,
title: currentTutorial.title,
description: currentTutorial.description,
published: status
};
TutorialDataService.update(currentTutorial.id, data)
.then((response: any) => {
console.log(response.data);
setCurrentTutorial({ ...currentTutorial, published: status });
setMessage("The status was updated successfully!");
})
.catch((e: Error) => {
console.log(e);
});
};
const updateTutorial = () => {
TutorialDataService.update(currentTutorial.id, currentTutorial)
.then((response: any) => {
console.log(response.data);
setMessage("The tutorial was updated successfully!");
})
.catch((e: Error) => {
console.log(e);
});
};
const deleteTutorial = () => {
TutorialDataService.remove(currentTutorial.id)
.then((response: any) => {
console.log(response.data);
navigate("/tutorials");
})
.catch((e: Error) => {
console.log(e);
});
};
return ( ... );
};
export default Tutorial;
And this is the code inside return
:
const Tutorial: React.FC<Props> = (props: Props) => {
...
return (
<div>
{currentTutorial ? (
<div className="edit-form">
<h4>Tutorial</h4>
<form>
<div className="form-group">
<label htmlFor="title">Title</label>
<input
type="text"
className="form-control"
id="title"
name="title"
value={currentTutorial.title}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label htmlFor="description">Description</label>
<input
type="text"
className="form-control"
id="description"
name="description"
value={currentTutorial.description}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<label>
<strong>Status:</strong>
</label>
{currentTutorial.published ? "Published" : "Pending"}
</div>
</form>
{currentTutorial.published ? (
<button
className="badge badge-primary mr-2"
onClick={() => updatePublished(false)}
>
UnPublish
</button>
) : (
<button
className="badge badge-primary mr-2"
onClick={() => updatePublished(true)}
>
Publish
</button>
)}
<button className="badge badge-danger mr-2" onClick={deleteTutorial}>
Delete
</button>
<button
type="submit"
className="badge badge-success"
onClick={updateTutorial}
>
Update
</button>
<p>{message}</p>
</div>
) : (
<div>
<br />
<p>Please click on a Tutorial...</p>
</div>
)}
</div>
);
};
export default Tutorial;
Add CSS style for React Typescript Components
Open src/App.css and write CSS code as following:
.list {
text-align: left;
max-width: 750px;
margin: auto;
}
.submit-form {
max-width: 300px;
margin: auto;
}
.edit-form {
max-width: 300px;
margin: auto;
}
Configure Port for React Typescript Client with API call
Because most of HTTP Server use CORS configuration that accepts resource sharing retrictted to some sites or ports, so we also need to configure port for our App.
In project folder, create .env file with following content:
PORT=8081
Now we’ve set our app running at port 8081
.
Run React Typescript App
You can run our App with command: npm start
.
If the process is successful, open Browser with Url: http://localhost:8081/
and check it.
This React Client will work well with following back-end Rest APIs:
– Express, Sequelize & MySQL
– Express, Sequelize & PostgreSQL
– Express, Sequelize & SQL Server
– Express & MongoDb
– Spring Boot & MySQL
– Spring Boot & PostgreSQL
– Spring Boot & MongoDB
– Spring Boot & SQL Server
– Spring Boot & H2
– Spring Boot & Cassandra
– Spring Boot & Oracle
– Python/Django & MySQL
– Python/Django & PostgreSQL
– Python/Django & MongoDB
Conclusion
Today we’ve built a React Typescript CRUD example with API call successfully with Axios & React Router. Now we can consume REST APIs, display, search and modify data in a clean way. I hope you apply it in your project at ease.
For larger data, you may need to make pagination:
React Pagination using Hooks example
You can also find how to implement Authentication & Authorization with following posts:
– React Typescript + Hooks: JWT Authentication (without Redux) example
– React Hooks + Redux: JWT Authentication example
If you need Form Validation with React Hook Form 7, please visit:
React Hook Form Typescript example with Validation
Or File upload example:
React Typescript File Upload example
Serverless with Firebase:
– React Hooks + Firebase Realtime Database: CRUD App
– React Hooks + Firestore example: CRUD app
Happy learning, see you again!
Further Reading
For more details about ways to use Axios, please visit:
Axios request: Get/Post/Put/Delete example
Integration:
– Integrate React with Spring Boot
– Integrate React with Node.js Express
If you want to work with table like this:
Please visit: React Table example: CRUD App | react-table 7
Fullstack:
– React Typescript + Spring Boot: CRUD example
– React + Spring Boot + MySQL: CRUD example
– React + Spring Boot + PostgreSQL: CRUD example
– React + Spring Boot + MongoDB: CRUD example
– React + Node + Express + MySQL: CRUD example
– React + Node + Express + PostgreSQL example
React Redux + Node + Express + MySQL: CRUD example
– React + Node + Express + MongoDB example
– React + Django + Rest Framework example
Source Code
You can find the complete source code for this tutorial on Github.
Use React Components instead: React Typescript example Project with Axios and Web API
Thanks for your marvelous tutorial! I really enjoyed reading it. have a nice morning!
Hello and thank you for publishing this tutorial>! I am working on doing something similar, though using fetch and for some reason this app will not work for me, getting this error blow. The app loads, but the API calls do not work.
(failed)net::ERR_CONNECTION_REFUSED
Hi, did you run any backend server I mentioned in the tutorial?