Sign In
Sign In

Using Axios with React

Using Axios with React
Hostman Team
Technical writer
React
06.12.2023
Reading time: 19 min

Axios is a JS library that provides an easy-to-use interface for executing HTTP requests in the browser and on the server side. It supports the Promise API and allows you to handle asynchronous requests. 

The library is widely used in various projects, including React, Vue.js, Angular, and other frameworks. It lets developers easily interact with the API and process data received from the server.

There are numerous benefits of using this library in React:

Ease of use: It has a simple and easy-to-understand interface, making it easy to use even for beginners. It allows developers to quickly send HTTP requests to the server and receive responses from it.

Versatility: Supports browsers and Node.js, making it ideal for client-side and server-side use in React projects.

Promises support: Returns a Promises object, making it ideal for handling modern JavaScript syntax and asynchronous operations.

Interceptors: Allows you to use interceptors so that requests and responses are processed before they are sent and after they are received. This is useful for adding headers, handling errors, and more.

Request cancellation: The library allows you to cancel requests, improving application performance and preventing unnecessary requests.

Support for request headers and parameters: Allows you to add request headers and parameters, which is useful when passing information to the server.

Broad functionality: Supports all major HTTP request methods: GET, POST, PUT, DELETE, etc., and many data types such as JSON, forms, and text.

Error handling: It has built-in error handling, which allows you to detect and handle errors that occur during the execution of requests.

The requirements for using Axios are: 

  • Node.js version 14 and later;

  • A project on React set up with create-react-app tool;

  • Basic knowledge of JS, HTML, and CSS.

In this article, we will learn how to use Axios with React and give examples of its application.

Installing Axios and importing it into a project

Step 1: Before you start working with Axios, you need to select a working project:

cd project_name

Or create a new one and then select it:

npx create-react-app project_name
cd project_name

We'll create a React project called hostman

Step 2: Next, you need to install the library using the npm package manager. To do this, run the following command in the terminal:

npm install axios

Step 3. After the download is complete, import the library into the component that requires its use:

import axios from 'axios';

Once the Axios library has been installed and imported into your React application, we can begin our work.

GET request

To send a GET request, use the axios.get() method, which accepts one parameter, the URL. You should not use it to send sensitive data, as it may be visible in the browser address bar and server logs.

Step 1. Move from the application directory to the src directory.

cd src

Step 2. Next, create a file with the .js extension:

nano Test1.js

Step 3. Now, let's move on to writing the code:

import React, { useEffect, useState } from "react";
import axios from "axios";

function Test1() {
  const [data, setData] = useState([]);

  useEffect(() => {
    axios
      .get("https://jsonplaceholder.typicode.com/users")
      .then((response) => {
        setData(response.data);
      })
      .catch((error) => {
        console.log(error);
      });
  }, []);

  return (
    <div>
      <h1>List of users:</h1>
      <ul>
        {data.map((user) => (
          <li key={user.id}>
            {user.name} ({user.email})
          </li>
        ))}
      </ul>
    </div>
  );
}

export default Test1;

In this example, Test1 sends a GET request to the specified service and displays the list of users on the page. The component uses two hooks: 

  • useEffect to execute the request; 

  • useState to store data received from the API. 

A hook is a function that allows you to use state and other React features in functional components. If the request failed to send or process, we output an error to the console.

As a result of the request, we'll receive a list of users.

This example and all others use the https://jsonplaceholder.typicode.com API, which provides fake data for testing purposes. Replace it with the URL you will use in your project.

POST request

POST requests send data to the server, such as forms with user data, images, or other files, or creating or updating records in a database.

POST requests can be safe if they don't change the server state, but they are not idempotent, which means that sending a duplicate request again may change the server state. To make them idempotent, you can set a special header, such as an Idempotency-Key, which allows the server to determine if the request has been sent before. 

You can also protect POST requests with CSRF tokens to prevent them from being forged by attackers.

To send a POST request, call the post() method and pass the data and URL to which you want to send it. 

Step 1: Open the previously created file for editing:

nano Test1.js

Step 2. Write new code:

import React, { useState } from "react";
import axios from "axios";

function Test1() {
  const [data, setData] = useState({ name: "", email: "" });
  const [response, setResponse] = useState("");

  const handleChange = (event) => {
    setData({ ...data, [event.target.name]: event.target.value });
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    axios
      .post("https://jsonplaceholder.typicode.com/users", data)
      .then((response) => {
        setResponse(response.data);
      })
      .catch((error) => {
        console.log(error);
      });
  };

  return (
    <div>
      <h1>Sending data to server</h1>
      <form onSubmit={handleSubmit}>
        <label>
          Name:
          <input
            type="text"
            name="name"
            value={data.name}
            onChange={handleChange}
          />
        </label>
        <br />
        <label>
          Email:
          <input
            type="email"
            name="email"
            value={data.email}
            onChange={handleChange}
          />
        </label>
        <br />
        <button type="submit">Send</button>
      </form>
      {response && (
        <p>
          Data sent successfully: {response.name} ({response.email})
        </p>
      )}
    </div>
  );
}

export default Test1;

In this example, we applied useState to store the data entered by the user in the form and the data received from the API. We also created two functions: 

  • handleChange to update the state of the form when the user changes the data;

  • handleSubmit to send a POST request when the form is submitted.

When the form is submitted, we send a POST request and process the received data using the setResponse method. If the request cannot be sent or processed, we output an error.

PUT request

PUT requests send data to a server, which will replace existing data. They are often used to update user information, web page content, or database data.

To send a PUT request, you need to call the put() method and pass the data and the URL of the resource to which you want to send it. 

Step 1: Open the component file for editing:

nano Test1.js

Step 2. Let's rewrite the code of the Test1.js file again:

import React, { useState } from "react";
import axios from "axios";

const Test1 = () => {
  const [postData, setPostData] = useState({ id: "", title: "", body: "" });
  const [putData, setPutData] = useState({ id: "", title: "", body: "" });

  const handleInputChange = (event) => {
    setPostData({ ...postData, [event.target.name]: event.target.value });
};

  const handleSubmit = (event) => {
    event.preventDefault();
    axios
      .put(`https://jsonplaceholder.typicode.com/posts/${postData.id}`, {
        title: postData.title,
        body: postData.body,
      })
      .then((response) => {
        setPutData(response.data);
        console.log(response);
      })
      .catch((error) => {
        console.log(error);
      });
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <div>
          <label htmlFor="id">ID: </label>
          <input
            type="text"
            name="id"
            value={postData.id}
            onChange={handleInputChange}
          />
        </div>
        <div>
          <label htmlFor="title">Title: </label>
          <input
            type="text"
            name="title"
            value={postData.title}
            onChange={handleInputChange}
          />
        </div>
        <div>
          <label htmlFor="body">Info: </label>
          <input
            type="text"
            name="body"
            value={postData.body}
            onChange={handleInputChange}
          />
        </div>
        <button type="submit">Update</button>
      </form>
      <div>
        <p>Response:</p>
        <p>ID: {putData.id}</p>
        <p>Title: {putData.title}</p>
        <p>Info: {putData.body}</p>
      </div>
    </div>
  );
};

export default Test1;

Here, useState controls two states: 

  • postData that contains the data we want to send with the PUT request; 

  • putData that contains data received in response to the request.

We also define two functions: 

  • handleInputChange that updates the postData state when the user adds data to the form;

  • handleSubmit that sends a PUT request and updates the putData state.

Finally, we display the received data in the putData after the successful execution of the request.

DELETE request

To send a DELETE request, you need to call the delete() method and pass it the URL of the resource you want to delete. After receiving the request, the server checks if the resource is on the server and, if it is, deletes it. If the resource is not on the server, it may return a 404 "Not Found" error.

Step 1: Open the component file for editing:

nano Test1.js

Step 2. Rewrite the Test1.js code again:

import React, { useState } from 'react';
import axios from 'axios';

const Test1 = () => {
  const [postId, setPostId] = useState(null);
  const [response, setResponse] = useState(null);

  const handleDelete = () => {
    axios.delete(`https://jsonplaceholder.typicode.com/posts/${postId}`)
      .then(res => setResponse(res))
      .catch(err => setResponse(err));
  }

  return (
    <div>
      <input type="number" placeholder="Enter Post ID" onChange={(e) => setPostId(e.target.value)} />
      <button onClick={handleDelete}>Delete Post</button>
      {response && (
        <div>
          <h2>Response</h2>
          <p>Status: {response.status}</p>
          <p>Data: {JSON.stringify(response.data)}</p>
        </div>
      )}
    </div>
  );
}

export default Test1;

In this component, we created a form where the user can enter the ID of the record they want to delete and submit a DELETE request using the axios.delete() method. We have also handled success and error responses using the then() and catch() methods respectively.

Let's check the result of the component. It is shown in the image below.

Fd22b479 6fbb 4b8f 8c62 8c3a173358d2

Error handling

Axios provides a convenient way to handle errors that occur when sending HTTP requests. The then() and catch() methods accept functions that will be executed depending on the request execution status (whether it was completed or an error occurred). 

Step 1: Open the component file for editing:

nano Test1.js

Step 2. Once again, rewrite the code of the Test1.js file:

import React, { useState } from "react";
import axios from "axios";

const Test1 = () => {
  const [error, setError] = useState(null);

  const handleButtonClick = () => {
    axios
      .get("https://jsonplaceholder.typicode.com/posts/invalid-url")
      .then((response) => {
        console.log(response);
      })
      .catch((error) => {
        setError(error);
      });
  };

  return (
    <div>
      <button onClick={handleButtonClick}>Send GET-request</button>
      {error && (
        <div>
          <h2>Error message:</h2>
          <p>{error.message}</p>
        </div>
      )}
    </div>
  );
};

export default Test1;

In the example above, we create an error state. It allows us to keep track of errors that occur when submitting requests. We then create a handleButtonClick function that sends a GET request to an invalid URL and, if an error occurs, uses the setError method to update the error state with an error message.

The return value of the component contains a button and a data block. The button calls the handleButtonClick function, and the data block is only displayed if the error is non-null or false. In the block, we display the error message using the message property of the error object.

Let's check the result. It is shown in the picture below.

9326c475 3059 47cb A97f Cd02e5a26864

In addition, Axios also provides a static isCancel() method that lets you check if an error results from canceling a request. This can be useful if you use CancelToken or AbortController to cancel a request. We'll talk about it further in the article.

Creating a base instance

A base instance is an object that contains configuration parameters and methods for creating requests.

To set up a base instance, you need to use the create() method and pass a settings object. In the settings object, you can specify a base URL for all requests, headers, an authorization token, and other parameters.

For example, if the application needs to send requests to the API with the base URL, you can create a base instance in the src directory as follows.

Step 1: Create a file with the .js extension:

nano basic.js

Step 2. Next, let's write the code:

import axios from 'axios';

const instance = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com/',
});

export default instance;

Step 3. Let's import an instance using the example from the "Error Handling" section:

import React, { useState } from "react";
import axios from "axios";
import instance from "./basic";

const Test1 = () => {
  const [error, setError] = useState(null);

  const handleButtonClick = () => {
  instance
      .get("invalid-url")
      .then((response) => {
        console.log(response);
      })
      .catch((error) => {
        setError(error);
      });
  };

...

export default Test1;

Here we changed the following lines: 

    instance
     .get("invalid-url")

And:

import instance from "./basic";

Using async and await

Async and Await are tools for managing asynchronous operations in JavaScript. They greatly simplify the code involved in handling query responses.

To use these tools, you need first to define a function that will be called asynchronously. Then, you can use the await keyword to call the Axios function and wait for it to fulfill the request.

Let's rewrite the code from the GET request section:

import React, { useEffect, useState } from "react";
import axios from "axios";

function Test1() {
    const [data, setData] = useState([]);

    useEffect(() => {
        async function asyncFunction() {
            try {
                const response = await axios.get("https://jsonplaceholder.typicode.com/users");
                setData(response.data);
            } catch (error) {
                console.log(error);
            }
        }
        asyncFunction();
    }, []);

return (
<div>
    <h1>List of users:</h1>
    <ul>
        {data.map((user) => (
        <li key={user.id}>
            {user.name} ({user.email})
        </li>
        ))}
    </ul>
</div>
);
}

export default Test1;

Here, we create asyncFunction, an asynchronous function that waits for a response from the server using the await keyword and sets the received data using setData

With these tools, you can avoid using callbacks or then chains which makes the code more readable. It is important to remember that they also require error handling to prevent blocking the execution flow and unexpected program behavior.

Canceling queries

If an application uses Axios to execute queries, you may need to cancel them at runtime. 

Here are some examples of when this may be required:

  • A user clicks on the “Cancel” button during a request to the server because they no longer want to wait for a response or have navigated to another page.

  • An error occurred in the application, and the request is no longer needed.

  • The user has started entering a new request, and we must cancel the previous one to avoid overloading the server with requests.

  • The application makes several successive requests to the server, and each request depends on the previous one. If one of these requests terminates with an error, the following requests may become useless, and we should cancel them to reduce the load on the server.

To cancel requests, use the standard AbortController API, added to browsers in ECMAScript 2017. This API provides a convenient mechanism for canceling any asynchronous operations, including requests to the server.

To use AbortController, create an instance with the same name and pass it as a request parameter using the signal method. 

Let's create an instance and declare its signal:

const controller = new AbortController();
const signal = controller.signal;

Then pass it to the query parameters:

axios.get('/user', { signal })
.then((response) => {
 console.log(response.data);
})

And add a cancel notification feature:

if (axios.isCancel(error)) {
   console.log('Request canceled', error.message);
}

To cancel the request, we need to call the abort() method on the instance. Let's add it at the end:

controller.abort();

Using the AbortController API to cancel requests instead of CancelToken is a simpler and more natural way since it is already the standard API for canceling asynchronous operations in the browser. This can also simplify code support and compatibility with other libraries and frameworks using this method.

Optimizing performance when using Axios

In this chapter, we will look at a few tips to optimize performance when using Axios in your project:

Request caching

Caching is useful when we have to send the same request multiple times within a short period of time. For this, we can use the axios-cache-adapter library or write our caching handler.

Minimizing the number of requests

Sometimes we can get all the data we need from the server in a single request, instead of sending separate requests for different data. When possible, we should combine multiple requests into one and get all the required data from the server.

Canceling requests

As we mentioned earlier, request cancelation can be useful when we send many requests or when the user switches between pages quickly. Un-canceled requests can overload the server and slow down the application's performance.

Deferred data download

In some cases, we can delay loading data until the user needs it. For example, we can load data only when the user scrolls the page down or opens a modal window. This can reduce the number of requests and speed up the application's performance.

Using interceptors

Interceptors allow us to manipulate requests and responses before they are sent or processed. We can use them to log requests and responses, handle errors, etc. However, using too many interceptors can degrade application performance.

Using memoization

You can use memoization libraries such as React.memo or useMemo to avoid re-rendering components that have not changed. This can reduce the number of requests to the server and improve performance.

Conclusion

Axios is a library for sending HTTP requests that can be used with React. In this article, we went over the basics of using Axios and gave some examples of its usage.

You can deploy React application on our App platform

React
06.12.2023
Reading time: 19 min

Similar

React

Optimizing Server Requests With React Hooks

In the world of modern web applications, efficient server request management is becoming an increasingly important task. The increased volume of requests can lead to slower performance, poor system responsiveness, and resource overuse. Developers aim to create applications that not only provide high-quality service to users but also make efficient use of available resources. React Hooks are functions from the React library that allow interaction with functional components, including managing state, context, lifecycle, and other aspects. With the introduction of React Hooks, developers gained an effective and versatile tool for configuring server interactions, allowing them to determine the timing and frequency of network requests accurately. In this React Hooks tutorial, we will thoroughly explore how the use of this tool contributes to the optimization of server requests. We will analyze various methods for managing application state that help reduce server load and enhance the user experience. By the end, you will learn how to integrate these methods into your React applications to create faster and more responsive interfaces. To follow all the steps outlined in this guide, you will need the following skills and tools: Basic knowledge of JavaScript and the ability to create a React application from scratch Understanding the basics of React Hooks Skills in performing server requests in JavaScript A working development environment A code editor Don’t worry if you're unfamiliar with server request optimization — this guide is intended for developers of all skill levels. If some concepts are new to you, you may need to conduct additional research and experiments and invest extra time in learning new material. Creating a New React Project Before diving into React application development, let's begin with the fundamental step—creating a new project. This initial stage lays the foundation for all subsequent development, and setting up the project correctly can greatly simplify the process of building and maintaining your code in the future. React, as one of the most popular libraries for building user interfaces, offers a variety of tools and templates to streamline and simplify the early stages of development. By leveraging modern tools and approaches such as Create React App (CRA), you can quickly create a stable, ready-to-use base that allows you to focus on writing functionality rather than configuring the environment. Before starting work on your project, ensure that your computer has all the necessary components for working with React, specifically Node.js and npm. Otherwise, download them from the official website. After installing these tools, open your terminal or command prompt, navigate to the directory where you want to create your application, and follow the instructions below based on the tool you prefer to work with: Create React App or Vite. Create React App Run the following command to initialize a new React project: npx create-react-app hostman-app Replace hostman-app with the actual name of your project. This command will download all the necessary dependencies and create a boilerplate project ready for development. If the application is successfully created, the console will display output similar to the following: Success! Created hostman-app at your_file_path/hostman-app Inside that directory, you can run several commands: npm start Starts the development server. npm run build Bundles the app into static files for production. npm test Starts the test runner. npm run eject Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back! We suggest that you begin by typing: cd hostman-app npm start Happy hacking! This will create a new directory with the name of your project containing all the necessary files. After the setup process is complete, navigate to the newly created directory using the following command: cd hostman-app Then, run the following command as instructed in the welcome message to start the development server: npm start If everything is done correctly, the server will start, and you should see the following output on your screen: Compiled successfully! You can now view hostman-app in the browser. http://localhost:3000 Note that the development build is not optimized. To create a production build, use npm run build. This will open your new React application in the default browser. You should see the React startup screen: You can now begin working with hooks in the App.js file, located at /hostman-app/src/. Vite To initialize a new React project with Vite, run the following command: npm create vite@latest hostman-app Replace hostman-app with the actual name of your project. This command will download all the necessary dependencies and create a boilerplate project ready for development. When prompted to install Vite, confirm by pressing -y. Select the React type of application. After the setup process is complete, navigate to the newly created directory using the command: cd hostman-app Then execute the following commands to start the development server: npm installnpm run dev If everything is done correctly, the server will start, and the address of your application will be displayed, such as: http://localhost:5173 Copy the address from the console and paste it into your browser's address bar. You should see the React welcome screen. You can now begin working with hooks in the App.jsx file, located at /hostman-app/src/. Synchronizing Components with the useEffect Hook Developing modern web applications with React requires special attention to managing side effects. These effects can include sending server requests, subscribing to data updates, modifying document headers, setting timers, and other actions beyond merely displaying information. The useEffect hook in React provides developers with a powerful tool to control these side effects in functional components, improving performance and making processes more transparent. One of the key and widely used applications of useEffect is making server requests and subsequently updating the component's state. An example of using the useEffect hook for server requests involves calling a function that performs the request inside this hook. The function can use the Fetch API or the Axios library to make the request and then update the component's state using the setState hook. Below is an example of using the useEffect hook to fetch data from the JSON Placeholder API and update the component's state. Navigate to the App.js or App.jsx file inside the src folder of your project. Delete the default code and replace it with the following example: import React, { useEffect, useState } from 'react'; function MyComponent() { const [data, setData] = useState([]); useEffect(() => { async function fetchData() { const response = await fetch('https://jsonplaceholder.typicode.com/posts'); const data = await response.json(); setData(data); } fetchData(); }, []); return ( <div> {data.map((item) => ( <div key={item.id}> <h2>- {item.title}</h2> <p>{item.body}</p> </div> ))} </div> ); } export default MyComponent; After importing standard hooks and declaring the functional component, we use the useState hook to create the data state and the setData function, which will be used to update this state. The initial state is an empty array since we expect a list of data. The useEffect hook performs an asynchronous API request during the component's initial render using the fetchData function. Using the .map method, we render each element from the updated data state as separate components. Each element includes a title and body. We assign item.id as a unique key for each <div> to enable React to identify and manage these components in the DOM efficiently. Finally, the MyComponent component is exported so it can be used in other parts of the application. If you refresh the browser or the application, you should see the result of the request displayed based on the provided code. An important aspect is minimizing unnecessary re-renders, which can negatively impact performance. Proper error handling when performing server requests is also critically important to prevent component failures. You can implement error handling by adding a try-catch block inside the fetchData function and using the setError hook to update the component's state with an error message. This way, the application can display an error message to the user if something goes wrong. Optimizing Server Request Performance with the useMemo Hook The useMemo hook in React is a performance optimization tool that allows developers to memoize data, storing the result of computations for reuse without repeating the process itself. useMemo returns a cached value that is recalculated only when specified dependencies change. This prevents costly computations on every component render. One effective way to use the useMemo hook in the context of server requests is to memoize data fetched from the server and then use it to update the component's state. To achieve this, you can call the useMemo hook inside a useEffect hook, passing the server data as the first argument and a dependency array as the second. The dependency array should include all props or state variables that affect the calculation of the memoized data. Below is an example of using the useMemo hook to memoize data from the JSON Placeholder API and update the component's state. Replace the code in the App.js / App.jsx file with the provided snippet. import { useEffect, useState, useMemo } from 'react'; function MyComponent({ postId }) { const [data, setData] = useState({}); useEffect(() => { async function fetchData() { const response = await fetch(`https://jsonplaceholder.typicode.com/posts/1`); const data = await response.json(); setData(data); } fetchData(); }, [postId]); const title = useMemo(() => data.title, [data]); return ( <div> <h2>{title}</h2> </div> ); } export default MyComponent First, we import the useEffect, useState, and useMemo hooks to manage the component's state. We use useState to create the data state and the setData function to update it. The initial state is an empty object, which will later hold the post information fetched from the server. Using the fetchData function, we make an API request, passing the postId parameter in the dependency array. This ensures that the effect is executed only when postId changes. Within the component, we use the useMemo hook to memoize the title by passing data.title as the first argument and [data] as the second argument, so the memoized value updates only when the data state changes. The subsequent steps are similar to the previous useEffect example. It is important to note that useMemo is not always necessary. You should use it only when the component depends on frequently changing props or state and when the value computation is expensive. Improper use of useMemo can lead to memory leaks and other performance issues. Managing Server Request State with the useReducer Hook The useReducer hook in React is similar to the useState hook but provides a more structured and predictable way of managing state. Instead of updating the state directly, useReducer allows you to dispatch actions that describe the state update and use a reducer function to update the state based on the dispatched action. One of the key benefits of using useReducer for managing server requests is improved organization of logic. Rather than spreading server request handling logic throughout the component, you can encapsulate it within the reducer. This makes the component's code cleaner, more readable, and easier to maintain. To try this approach using the useReducer hook for managing data fetched from the JSON Placeholder API and updating the component's state, replace the code in the App.js / App.jsx file with the provided snippet. import { useReducer } from 'react'; const initialState = { data: [], loading: false, error: '' }; const reducer = (state, action) => { switch (action.type) { case 'FETCH_DATA_REQUEST': return { ...state, loading: true }; case 'FETCH_DATA_SUCCESS': return { ...state, data: action.payload, loading: false }; case 'FETCH_DATA_FAILURE': return { ...state, error: action.payload, loading: false }; default: return state; } }; function MyComponent() { const [state, dispatch] = useReducer(reducer, initialState); const fetchData = async () => { dispatch({ type: 'FETCH_DATA_REQUEST' }); try { const response = await fetch('https://jsonplaceholder.typicode.com/posts'); const data = await response.json(); dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data }); } catch (error) { dispatch({ type: 'FETCH_DATA_FAILURE', payload: error.message }); } }; return ( <div> {state.loading ? ( <p>Loading...</p> ) : state.error ? ( <p>{state.error}</p> ) : ( <div> {state.data.map((item) => ( <div key={item.id}> <h2>{item.title}</h2> <p>{item.body}</p> </div> ))} </div> )} <button onClick={fetchData}>Load data</button> </div> ); } export default MyComponent; In the code snippet above, we call the useReducer hook with a reducer function and an initial state passed as arguments. Initially, the component's state is set up as follows: An empty array for storing data A loading variable set to false An empty string for displaying error messages Clicking the "Load Data" button triggers the fetchData function. This function dispatches actions based on the result of the request: either a successful response or an error. Additionally, the useReducer hook allows for more effective management of complex states. Using actions and reducers to update the state simplifies handling how different actions affect various parts of the state, making adding new features and debugging issues in the application easier. Conclusion This guide has covered the basics of optimizing server requests using React Hooks. Optimizing server requests is essential for improving the performance and usability of your web application. In this article, we explored key techniques for request optimization: Caching results with useMemo Centralized state management of requests with useReducer Efficient use of useEffect for performing asynchronous operations dependent on your component's state parameters Understanding and applying these optimization methods reduces response time, decreases server load, and enhances the overall user experience. Mastering these techniques will help you build more efficient and responsive applications ready to handle various loads and usage scenarios. Once you’ve mastered the basic hooks, several advanced concepts are worth exploring for more sophisticated state and logic management in React applications. Here are some additional hooks to consider: useContext. This hook allows access to a context created using React.createContext. It enables you to share information between components in a hierarchy without passing props at every level. useCallback. This hook provides a memoized version of a callback function, which updates only when dependencies change. It's a tool for improving application performance. useRef. This hook returns an object with a .current property, useful for persisting values across renders without triggering re-renders. useImperativeHandle. Used with React.forwardRef to customize the instance value assigned to a parent component when using refs. useLayoutEffect. Similar to useEffect, but it runs synchronously after all DOM changes. It's helpful when you need to measure and modify the DOM immediately after rendering. These hooks provide powerful tools for managing component state and behavior in React, each with unique use cases and benefits. Exploring and incorporating them into your projects can help you create highly dynamic, efficient, and maintainable applications. In addition, you can deploy React applications on our platform as a service.
31 January 2025 · 13 min to read
React

How to Create a Telegram Mini App with React

A Telegram Mini App is a web application that opens inside the Telegram messenger. These apps are built with standard web technologies like HTML, CSS, and JavaScript, and they look like regular websites. In this article, we'll create a Mini App using React and deploy it with Hostman App Platform. Preparation You'll need Node.js installed to develop a Mini App. You can download it from the official website. We recommend keeping the default installation path to avoid potential issues. Development We will create a memory card game as an example. The goal is to match pairs of colors and earn points, with an option to share your score in Telegram chats. Project Setup Open the terminal: Start the Windows console or another terminal. Choose a directory: Navigate to the folder where you want to create the project. For example, to create it on your desktop, enter: cd Desktop Create a project: Use the following command to create a new React project: npx create-react-app memory-game Here, memory-game is the name of the project folder. You can choose any other name. Open the project in an editor: I recommend using Visual Studio Code (VS Code), but you can use any other code editor. Writing the Code You should execute all commands for installing libraries and running the project inside the project directory. If you encounter issues, make sure you're in the correct directory. The structure of the created folder looks like this. The necessary files for development will be created in the src folder. Verify that the React app runs locally by entering: npm start This will start the project, and a new browser tab will open. Install the Telegram SDK: npm install @telegram-apps/sdk Initialize the Telegram SDK: To emulate the Telegram Mini App environment during development, you need to handle the fact that the code is not running in a Mini App environment. Open the index.js file and add the following code: import React from 'react'; import { createRoot } from 'react-dom/client'; import App from './App'; import { initMiniApp, mockTelegramEnv, parseInitData } from '@telegram-apps/sdk'; const initializeTelegramSDK = async () => { try { // Attempt to initialize the real Telegram environment console.log("Initializing Telegram environment"); const [miniApp] = initMiniApp(); await miniApp.ready(); } catch (error) { // In case of an error, initialize a mock environment console.error('Error initializing Telegram:', error); const initDataRaw = new URLSearchParams([ ['user', JSON.stringify({ id: 99281932, first_name: 'Andrew', last_name: 'Rogue', username: 'rogue', language_code: 'en', is_premium: true, allows_write_to_pm: true, })], ['hash', '89d6079ad6762351f38c6dbbc41bb53048019256a9443988af7a48bcad16ba31'], ['auth_date', '1716922846'], ['start_param', 'debug'], ['chat_type', 'sender'], ['chat_instance', '8428209589180549439'], ]).toString(); mockTelegramEnv({ themeParams: { accentTextColor: '#6ab2f2', bgColor: '#17212b', buttonColor: '#5288c1', buttonTextColor: '#ffffff', destructiveTextColor: '#ec3942', headerBgColor: '#fcb69f', hintColor: '#708499', linkColor: '#6ab3f3', secondaryBgColor: '#232e3c', sectionBgColor: '#17212b', sectionHeaderTextColor: '#6ab3f3', subtitleTextColor: '#708499', textColor: '#f5f5f5', }, initData: parseInitData(initDataRaw), initDataRaw, version: '7.2', platform: 'tdesktop', }); console.log('Mock Telegram environment initialized'); } }; // Initialize SDK initializeTelegramSDK(); const container = document.getElementById('root'); const root = createRoot(container); root.render( <React.StrictMode> <App /> </React.StrictMode> ); Writing the Game Logic Next, we write the core game logic for our memory card game in App.js. The game will have a limited number of turns (15), and it will track the score, display win/lose screens, and save the score in local storage. import React, { useReducer, useEffect } from 'react'; import './App.css'; const generateDeck = () => { const colors = ['#FF6347', '#4682B4', '#32CD32', '#FFD700', '#FF69B4', '#8A2BE2']; const deck = []; // Add two cards for each color for (let color of colors) { deck.push({ color, matched: false }); deck.push({ color, matched: false }); } // Shuffle the deck return deck.sort(() => Math.random() - 0.5); }; const initialState = { deck: generateDeck(), flipped: [], matched: [], turns: 0, score: 0, pendingReset: false, gameOver: false, }; const gameReducer = (state, action) => { switch (action.type) { case 'FLIP_CARD': // Flip the card if (state.flipped.length < 2 && !state.flipped.includes(action.index) && !state.matched.includes(state.deck[action.index].color)) { return { ...state, flipped: [...state.flipped, action.index] }; } return state; case 'CHECK_MATCH': // Check if flipped cards match const [first, second] = state.flipped; if (state.deck[first].color === state.deck[second].color) { const newMatched = [...state.matched, state.deck[first].color]; const isGameOver = newMatched.length === state.deck.length / 2; return { ...state, matched: newMatched, score: isGameOver ? state.score + 1 : state.score, flipped: [], pendingReset: false, gameOver: isGameOver, }; } else { return { ...state, pendingReset: true }; } case 'RESET_FLIPPED': // Reset flipped cards return { ...state, flipped: [], pendingReset: false }; case 'INCREMENT_TURN': // Increment the turn counter return { ...state, turns: state.turns + 1 }; case 'RESET_GAME': // Reset the game state return { ...initialState, deck: generateDeck(), }; default: return state; } }; const App = () => { const [state, dispatch] = useReducer(gameReducer, initialState); // Check for a match when two cards are flipped useEffect(() => { if (state.flipped.length === 2) { dispatch({ type: 'CHECK_MATCH' }); dispatch({ type: 'INCREMENT_TURN' }); } }, [state.flipped]); // Timer to reset flipped cards useEffect(() => { if (state.pendingReset) { const timer = setTimeout(() => { dispatch({ type: 'RESET_FLIPPED' }); }, 1000); return () => clearTimeout(timer); } }, [state.pendingReset]); // Handle card click event const handleCardClick = (index) => { if (!state.gameOver && state.flipped.length < 2 && !state.flipped.includes(index)) { dispatch({ type: 'FLIP_CARD', index }); } }; const handlePlayAgain = () => { dispatch({ type: 'RESET_GAME' }); }; return ( <div className="App"> <h1>Memory Game</h1> <div className="info"> <p>Score: {state.score}</p> <p>Attempts: {state.turns}/15</p> </div> <div className="deck"> {state.deck.map((card, index) => ( <div key={index} className={`card ${state.flipped.includes(index) || state.matched.includes(card.color) ? 'flipped show' : ''}`} style={{ '--card-color': card.color }} onClick={() => handleCardClick(index)} /> ))} </div> {state.gameOver && ( <> <div className="overlay" /> <div className="game-over"> <h2>You won!</h2> <button onClick={handlePlayAgain}>Play Again</button> </div> </> )} {!state.gameOver && state.turns >= 15 && ( <> <div className="overlay" /> <div className="game-over"> <h2>Game Over!</h2> <button onClick={handlePlayAgain}>Play Again</button> </div> </> )} </div> ); }; export default App; Adding Styles You must also write CSS styles to make the game look visually appealing. When writing CSS, it's important to understand that elements should preferably be placed in the center or anchored to the edges of the screen. This ensures that when they shift, the app's elements also shift accordingly. After all, a Mini App is essentially a website optimized for phone screens. In App.css, write the following styles: body { font-family: 'Arial', sans-serif; background-color: #f0f0f0; display: flex; justify-content: center; align-items: center; background: linear-gradient(to right, #ffecd2, #fcb69f); } /* Additional styling here */ When creating a Telegram Mini App, keep in mind that you need to optimize the application for a specific screen size. To control this size, you can use the DevTools in your browser. To open DevTools, press the F12 key. After that, click on the icon that shows a laptop and a phone. Now the app will appear as a website opened on a phone. You need to adjust the screen dimensions slightly. Enter 350 for the width (first field) and 670 for the height (second field). This size will be the approximate resolution of the Mini App. Code Improvement At the moment, the documentation for @telegram-apps/sdk does not include expand. This feature ensures that when you open the Telegram Mini App on a phone, it opens in full screen rather than only taking up half of it. To add expand, open the index.html file located in the public folder, and add the following code after the opening <head> tag: <script src="https://telegram.org/js/telegram-web-app.js"></script> <script> Telegram.WebApp.expand(); </script> Here, the connection to the library for creating a Mini App is established directly through a script, and the expand feature from this library is used. Let’s add a bit of color to the header in the Telegram Mini App. To do this, add the following code after initializing the Mini App in index.js: miniApp.setHeaderColor('#fcb69f'); Now header looks like this: Let's also add the ability to share your score in other Telegram chats using the MainButton provided by the SDK. We'll modify index.js. The import now looks as follows: import { initMiniApp, initMainButton, mockTelegramEnv, parseInitData, initUtils } from '@telegram-apps/sdk'; And after setting the header color, you need to add the following code to get the score from the game and insert it into a message. This message can then be forwarded to other chats in Telegram. // Initialization of the main button const [mainButton] = initMainButton(); mainButton.setParams({ backgroundColor: '#aa1388', text: 'Share Score', isVisible: true, isEnabled: true, }); mainButton.show(); const utils = initUtils(); // Setting up the click handler for the main button mainButton.on('click', () => { try { // Getting the current score from localStorage const score = localStorage.getItem('memory-game-score') || 0; utils.shareURL(`Check it out! I have ${score} points in the game!`); console.log('Chat selection window opened for sending the message.'); } catch (error) { console.error('Error opening the chat selection window:', error); } }); Deployment Next, we need to make our Telegram application available to other users. For this, we will upload the code to GitHub and then deploy the application to a server. Uploading Code to GitHub Once the Mini App is ready, you need to upload the files from the folder to GitHub. Create a new private repository on GitHub, then return to your project. Using the command line (make sure you are in the project folder), upload all files to your repository. Enter these commands sequentially: Initialize a new Git repository in the current directory: git init Add all changes (new, modified, and deleted files) in the current directory to the next commit. Enter the command with the dot at the end: git add . Create a commit with the message "first commit," recording all changes added with the git add command: git commit -m "first commit" Rename the current branch to main and set it as the default branch. The -M flag means "rename": git branch -M main Add a remote repository named origin and link it to the specified URL. Provide the link to your newly created repository: git remote add origin https://github.com/my-account/memory-game Push changes from the local main branch to the remote main branch on the origin repository. The -u flag sets up a tracking relationship between the local and remote branches so that you can use git push without additional parameters in the future: git push -u origin main Deploying the Mini App After uploading your files to GitHub, you can upload the application to the server. I will be deploying the React Mini App using Hostman's App platform. If you are not yet a Hostman client, register first. Go to the App platform section and start creating an app. Choose the Frontend type and the React framework. You will need to link your GitHub profile to upload projects. Next, enter the repository name you specified during creation. In the Region section, choose the one closest to you, where the ping is the lowest. In the configuration, select the request limit you need. Do not change anything in the application settings. In the application information section, specify its name and any comments, and select the project to which your application will be linked. Next, click the Deploy button, which will start the automatic deployment of your React application to the server. After some time, the application will start, and if the deployment is successful, the deployment logs will display "Deployment successfully completed." When the application starts, you will also get a free domain linked to the application. You can find it in the Settings section of your application. To visit the domain and check if everything is working, simply copy it and paste it into your browser's address bar. Preparing a Telegram Bot for Mini App You need to create and configure a Telegram bot to ensure that the Mini App opens within Telegram. Follow these steps: Step 1. Creating the Bot Go to the official BotFather bot and start a chat with it. Enter the command /newbot. The bot will ask you to provide a name for the bot. After entering the name, the bot will request a username. This username must end with the word bot. For example, if your bot's name is Tetris, the username can be: TetrisBot Tetric_bot Tetrisbot Tetris_Bot If successful, the bot will send you a message with your new bot's details and the token. Never share the bot token with people you do not trust. Step 2. Configuring the Bot: To configure the bot, enter the command /mybots. The bot will send a list of your created bots. Select the desired bot using the inline buttons. You will see a menu like this: Clicking on "Edit Bot" allows you to add an avatar, a description in the "About" section (which appears when entering the bot), a photo for the description, and to change the bot’s name. You can skip these actions if the application is still in development. Adding a Button to Open Telegram Mini App: Add a button to open the Telegram Mini App. Go to "Bot Settings", then select "Menu Button" and within that, "Configure menu button". When you click these buttons, the bot will ask you to send a link to your Mini App. Go back to Hostman and copy the URL where your application is hosted. After sending the URL, the bot will ask you to enter a name for the button. Step 3. Testing the Bot Now, you can go to the bot and press the "Start" button to send the "Start" command. The bot won’t respond as there is no code written for responses yet, but what you need is the button in the lower left corner. When clicked, it will open the Telegram Mini App. Step 4. Adding Screenshots You can add screenshots of your Telegram application to your bot's description. Currently, this feature is available only on mobile devices and only after some time has passed since creating the bot (and only if your Mini App is actively used). Analytics and Monetization You’ve created a Telegram Mini App and want to showcase it to others and launch it globally. But what if you want to collect statistics from your Mini App?  In addition to analytics, if your Telegram Mini App is a game, you might want to add monetization so that people watch ads and get something in return, while you earn revenue. Analytics Recently, a service specializing in collecting analytics for Telegram Mini Apps has been introduced. It’s called Telemetree. With it, you can gather various information: Number of Telegram Mini App users: Total number New users Returning users User device Event count: How many times and which buttons were clicked Highest activity Day of the week when the Telegram Mini App is used most frequently Most active time Session duration This service is currently being developed so we may expect new tracking options for different events in the future. To start collecting data, you need to register on the project’s website. After registration, you will receive an Application ID and Project ID. These keys should not be shared with anyone. Now, you need to install their library using the command: npm install @tonsolutions/telemetree-react --save After installation, open the index.js file and add the import: import { TwaAnalyticsProvider } from '@tonsolutions/telemetree-react'; Then update the render method to start collecting analytics after rendering your application. Replace projectId and apiKey with the values provided during registration, and enter your product name in appName: root.render( <React.StrictMode> <TwaAnalyticsProvider projectId='YOUR_PROJECT_ID' apiKey='YOUR_API_KEY' appName='YOUR_APPLICATION_NAME' > <App /> </TwaAnalyticsProvider> </React.StrictMode> ); After completing these steps: Upload the changes to the server using Git. When the data updates and a new build appears in Hostman, launch your Telegram Mini App and click on a few buttons to start collecting analytics. Return to the website, refresh the page, and then click the "Proceed" button. Monetization To add monetization to your Telegram Mini App, you need to use Adsgram. It provides rewards for watching ads in Ton. Go to the Adsgram website and create an app owner profile by clicking the "For app owner" button. After registration, click "Create…" in the upper left corner and select "platform". In the window that opens, enter the application name, the Telegram Mini App link, and the website where the application is hosted. To get the link to the Telegram Mini App, go back to BotFather and enter the command /newapp. A list of your bots will appear. Select the bot linked to the Telegram Mini App link. The bot will ask you to enter the application name, a brief description, and to send a photo. You can also send a GIF for the application, but you can skip this step by entering the command /empty. The bot will then ask for the website link where your application is hosted. Return to Hostman and copy the link again. Finally, the bot will ask you to send a short name for the Telegram Mini App. Go back to the Adsgram website and enter this direct link to the Mini App in the "Telegram Direct Link" field. After creating the platform, click "Add ad block" in the upper right corner to create an ad block. Enter a name for the block. For "Minimum cost per mine," it is advisable not to change the value from "Do not fill in" to "Fill in." You can also choose the type of ad: it will be either a video or a promotional post. Once you’ve created the ad block, open the index.js file and add the following script in the head tag: <script src="https://sad.adsgram.ai/js/sad.min.js"></script> Create a new file named useAdsgram.js and place the following code in it: import { useCallback, useEffect, useRef } from 'react'; export function useAdsgram({ blockId, onReward, onError }) { const AdControllerRef = useRef(undefined); useEffect(() => { AdControllerRef.current = window.Adsgram?.init({ blockId }); }, [blockId]); return useCallback(async () => { if (AdControllerRef.current) { AdControllerRef.current .show() .then(() => { onReward(); }) .catch((result) => { onError?.(result); }); } else { onError?.({ error: true, done: false, state: 'load', description: 'Adsgram script not loaded', }); } }, [onError, onReward]); } Then open app.js, where the game logic is located. Add a new import and modify the game logic to include two buttons on the game-over menu: one to restart the game and another to earn additional turns by watching an ad. You can now start a new game or watch an ad to receive 5 extra turns. Add the new import for the newly created hook: import { useAdsgram } from './useAdsgram';  // Import the created hook Then, at the end of gameReducer, add: case 'ADD_EXTRA_TURNS': return { ...state, turns: state.turns - 5, }; In the game components, in const App, add: const showAd = useAdsgram({ blockId: 'YOUR_BLOCK_ID', onReward: () => dispatch({ type: 'ADD_EXTRA_TURNS' }), onError: (error) => console.error('Error showing ad:', error), }); Replace blockId with your block ID, which can be obtained by clicking "Show code" in the ad block menu. Add a new button to the game-over menu: <div className="game-over">  <button onClick={showAd}>+5 Turns</button></div> Now, after losing the game, in addition to the "Play Again" button, you will also have a "+5 Turns" button, which will show an ad and grant the user 5 extra turns. Moderation According to the new Adsgram platform rules, to show ads in your Telegram Mini App, you need to pass moderation by contacting support via Telegram. To pass moderation, you must: Attach a screenshot from BotFather showing the Direct Link and Web App URL. Provide a link to your platform in the format https://partner.adsgram.ai/platforms/xxx/. Platforms that will not pass moderation include: Games where every click leads to an ad. Games where ads are shown immediately after a loss. Cheap game clones created to increase ad views. Services for inflating statistics and ads. Services where you need to watch ads to perform certain actions. Conclusion Creating a Telegram Mini App using React allows developers to build interactive and user-friendly applications integrated into the Telegram ecosystem. This guide presented a step-by-step process for creating a simple memory card game, including setting up the environment, writing the core code, styling the app, and integrating analytics and monetization. By applying this knowledge, you can create engaging and useful Mini Apps and effectively utilize Telegram's resources for distribution and monetization. The analytics and ad integration options discussed will aid in further developing and improving your Telegram applications.
24 September 2024 · 19 min to read
React

Using Font Awesome 5 with React

Font Awesome is an icon font that contains symbols and glyphs instead of numbers and letters. The font creators released the first set of icons in 2012, and since then, it's been used on at least 100 million websites. The icon collection is constantly growing, and new ways to integrate them into the web environment with frameworks are being developed. If you're already familiar with the benefits, features, and structure of Font Awesome, you can jump straight to the practical part. We've prepared a detailed guide on how to add icons to your project. For beginners in web development, we recommend carefully studying the entire material before implementing your ideas. Introduction to Font Awesome 5 The new version of Font Awesome was released not too long ago and quickly gained popularity. Developers and designers noticed several key improvements: Modern responsive icon design Animated icons Two versions: 1608 free & 7864 pro icons 4 styles New grid system Better readability at small sizes Although users worldwide have access to the same icon packages, they can be easily customized. We'll show you how to change the color, size, and position of Font Awesome icons using CSS and fully transform their appearance. How to Use Font Awesome 5 with React Before setting up Font Awesome in React, decide which icons you need. To avoid importing all of them, they've been divided into 4 packages based on their styles. Pay attention to the three-letter abbreviations, as you'll use these in the next steps. Four icon styles: Solid (fas) Regular (far) Light (fal) Brands (fab) The Free Solid package is entirely free, while the other 3 are part of the paid version. You can find the entire icon collection on the official Font Awesome website. You can filter icons by style and download the ones you like. Installing the Package Once you’ve familiarized yourself with the icon styles, you can begin integrating Font Awesome into your React project. In this guide, we’ll use NPM (Node Package Manager) for installation, although you can also use Yarn. To install Font Awesome core and solid icons, run: npm i --save @fortawesome/fontawesome-svg-corenpm install --save @fortawesome/free-solid-svg-iconsnpm install --save @fortawesome/react-fontawesome Or with Yarn: yarn add @fortawesome/fontawesome-svg-coreyarn add @fortawesome/free-solid-svg-iconsyarn add @fortawesome/react-fontawesome To install all icon styles (including pro versions if you have access), you can run the following commands: npm i --save @fortawesome/fontawesome-svg-core @fortawesome/react-fontawesome npm i --save @fortawesome/free-regular-svg-icons npm i --save @fortawesome/pro-regular-svg-icons npm i --save @fortawesome/free-solid-svg-icons npm i --save @fortawesome/pro-solid-svg-icons npm i --save @fortawesome/free-light-svg-icons npm i --save @fortawesome/pro-light-svg-icons npm i --save @fortawesome/free-brands-svg-icons Now that you’ve installed the packages, you need to import the icons into your application. Importing Icons Method 1. Explicit Icon Import This method allows you to import icons individually in each React component. This is useful if you only need a few icons and want to keep the JavaScript bundle small. However, this method can become cumbersome if the same icon is used in multiple places. Here’s an example of how to import icons explicitly: import ReactDOM from 'react-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCocktail } from '@fortawesome/free-solid-svg-icons'; const element = <FontAwesomeIcon icon={faCocktail} />; ReactDOM.render(element, document.body); Method 2. Creating an Icon Library This method is more efficient, especially for larger projects. Instead of importing icons individually, you can create a Font Awesome icon library. Once added, you can reference icons anywhere in your React application without importing them again. Here’s how you can create a library: import ReactDOM from 'react-dom'; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCocktail, faBomb } from '@fortawesome/free-solid-svg-icons'; library.add(faCocktail, faBomb); const App = () => ( <div> <FontAwesomeIcon icon="bomb" /> Favorite Drink: <FontAwesomeIcon icon="cocktail" /> </div> ); ReactDOM.render(<App />, document.body); Editing Icons Once you’ve imported the icons into your project, you can start customizing them. Here are a few ways to modify icons: Icon Size Font Awesome 5 lets you adjust the size of icons with size options such as xs, sm, lg, or by multiplying the size using numbers (2x, 3x, etc.). <FontAwesomeIcon icon="spinner" size="2x" /><FontAwesomeIcon icon="spinner" size="lg" /> Icon Rotation and Flip You can rotate icons or flip them horizontally or vertically: <FontAwesomeIcon icon="spinner" flip="horizontal" /><FontAwesomeIcon icon="cocktail" rotation={90} /> Icon Color To change the color of an icon, simply use CSS: <FontAwesomeIcon icon="square" color="green" /> Icon Animation Add animations such as spinning or pulsing: <FontAwesomeIcon icon="spinner" spin /><FontAwesomeIcon icon="spinner" pulse /> Power Transforms With power transforms, you can combine transformations like moving, shrinking, and rotating in one line: <FontAwesomeIcon icon="spinner" transform="shrink-6 left-4" /><FontAwesomeIcon icon="spinner" transform={{ rotate: 45 }} /> Conclusion Font Awesome is an excellent tool for adding social media icons, logos, and other symbols to your React application. With the ability to customize and animate icons, you can create a unique and recognizable app design. You can deploy React application on our App platform. 
24 September 2024 · 5 min to read

Do you have questions,
comments, or concerns?

Our professionals are available to assist you at any moment,
whether you need help or are just unsure of where to start.
Email us
Hostman's Support