Sign In
Sign In

Using Font Awesome 5 with React

Using Font Awesome 5 with React
Hostman Team
Technical writer
React
24.09.2024
Reading time: 5 min

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-core
npm install --save @fortawesome/free-solid-svg-icons
npm install --save @fortawesome/react-fontawesome

Or with Yarn:

yarn add @fortawesome/fontawesome-svg-core
yarn add @fortawesome/free-solid-svg-icons
yarn 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

React
24.09.2024
Reading time: 5 min

Similar

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 Axios with React

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_namecd 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. 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. 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. 
06 December 2023 · 19 min to read
React

Deploy a React App

Sooner or later, software developers face the task of automatically deploying projects to a remote host. They also often use cloud servers because they're easy to scale. In this article, we will learn how to deploy React applications to web hosting or a cloud server and also review deployment using an archive.  Getting ready We will need GitLab hosting with access for developers as users (without a secure SSH channel), a React project with regular updates, FTP support, and domain hosting. We'll also need a Node.js platform and a compiled project on a production computer. As soon as there are any changes in the repository, we should:  Compile React source code with the Node.js functionality. Clean the hosting from old information. Copy the newly compiled data there. Git Hooks You can check git hooks with the terminal command:  git help hooks Git hooks can be client and server hooks. The former are executed on the user's computer and the latter on the host. The client-side ones are located at .git/hooks. For any of them to function, you need to remove the .sample file. In our case, the pre-push will work to organize the auto-update of the repository, which is triggered before the start of copying information to the remote host. In GitLab, server-side hooks are called WebHooks. They are used, for example, when a request like a repository update comes in and is sent to a given HTTP address. This approach simplifies tracking the events inside the project and allows you to handle them promptly when deploying applications. Deploying the project to web hosting The web-hosting functionality allows you to implement the following: Start a pre-push hook that activates React project processing. It will create a repository and then copy the finished product to GitLab, where we'll store it in compiled form. Set up WebHook, which calls a script from the host to create a copy of the repository to a user-specified location (the result will be a web portal update). To connect to the repository, we'll use a login and password. Below, we will use this method of authentication as a basic one. Let's move on to creating a repository for the React project. For this purpose, we will generate a build.bash file in the source directory, and fill it with the following content: #!/bin/shcd /var/www/html/my-app/npm run-script buildcd /var/www/html/my-app/build/git initgit add .git commit -m 'build'git push -f --set-upstream https://login:[email protected]/my-app-build.git master This list of commands will allow you to go to the React project directory, start compilation, and then return to the build folder and create a local repository. As a result, you will copy the build to a remote host with a forced overwriting of the repository information. Now go to the .git/hooks directory and create a pre-push there, inserting the following content in it: #!/bin/shnohup /var/www/html/my-app/build.bash & The & symbol in the nohup command hides the terminal output. In our case, version control does not work, so when we rewrite the repository, we'll erase all the previously made and deleted comments. The created repository works as a "reaction point" necessary for the final stage of React application deployment. Let's finalize the procedure by converting both files into executable files: chmod 775 /var/www/html/my-app/build.bash /var/www/html/my-app/.git/hooks/pre-push When generating a WebHook for a project on GitLab, let's set a URL script, a secret token identifying the source, and mark push. Let's also write a PHP script to place in the web hosting root folder. Let's call it _deploy-client.php and include the following code: //write information about the last request to the test filefile_put_contents(dirname(__FILE__)."/".basename(__FILE__, ".php").".txt", print_r($_SERVER, true));//check that the request came from the right git host and that the token is correctif($_SERVER["REMOTE_ADDR"] != "xxx.xxx.xxx.xxx.xxx" || $_SERVER["HTTP_X_GITLAB_TOKEN"] != "sdf51s65dg1sd31fs3df1w6rg")    exit();//if the script has reached this point, it can be deployed//directory to copy to$sDir = dirname(__FILE__)."/client";//delete old build versionshell_exec("rm -rf $sDir/* $sDir/.[^.]*");//clone repository with build to the correct directoryshell_exec("git clone https://login:[email protected]/my-app-build.git $sDir/"); Deploying with an archive Using this option, we will replace the build repository with an archive. All you have to do is fix the contents of the build.bash file: #!/bin/shcd /var/www/html/tilda.local/htdocs/my-app/npm run-script buildcd buildzip -r build.zip *curl --data-binary @build.zip https://domain.zone/__deploy/client.php?token=token In our example, we have specified the archive format as ZIP. We also need to modify the web-hosting deploy script slightly: //write information about the last request into the filefile_put_contents(dirname(__FILE__)."/".basename(__FILE__, ".php").".txt", print_r($_SERVER, true).print_r($_FILES, true));//check tokensif($_GET["token"] != "token")    exit();//file to write POST data to (archive is there)file_put_contents(dirname(__FILE__)."/build.zip", file_get_contents('php://input'));//directory to deploy to$sDir = $_SERVER["DOCUMENT_ROOT"]."/client";//delete everything from the directoryshell_exec("rm -rf $sDir/* $sDir/.[^.]*");//unpack the archive into the directoryshell_exec("unzip -d $sDir/ build.zip "); When using the post-commit hook, you can deploy the React app without a git server. - Deploying React applications to a VPS As with web hosting, we will need a React project, which we will deploy to a virtual machine. For example, let's create a new application in the local environment: npx create-react-app react-deploy The command runs the Node package without downloading it to the computer. The create-react-app script installs all the necessary dependencies and creates a project in the react-deploy directory. This procedure will take a few minutes to complete. The system will display the result on the screen: Success! Created react-deploy at your_file_path/react-deployInside that directory, you can run several commands:  npm start    Starts the development server.  npm build    Bundles the app into static files for production.  npm test    Starts the test runner.  npm 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 react-deploy  npm startHappy hacking! Once we create the project, we should convert it into a production build.  npm run build It will compile JavaScript and assets into the build directory, containing compiled and minimized versions of all the project files.  Files location on an Ubuntu server We will rent a virtual machine VPS with a pre-installed Ubuntu operating system. Next, we'll install the Nginx web server and manually specify where to store the deployed project files.  First, let's determine the default root directory. To do this, connect to the remote host via a secure SSH channel: ssh username@server_ip Now let's check the configuration file's contents: cat /etc/nginx/sites-enabled/your_domain If there is no SSL certificate, we will see roughly the following output: server {        listen 80;        listen [::]:80;        root /var/www/your_domain/html;        index index.html index.htm index.nginx-debian.html;         server_name your_domain www.your_domain;        location / {                try_files $uri $uri/ =404;        }} Check the line starting with root. This is the path to store the project files after deployment. Uploading the build with SCP The scp command is one of the safest ways to transfer project files to a virtual machine. If you have a configured SSH key, it will use it by default. Otherwise, the system will prompt you to enter a login and password. To copy all the files, use the * symbol: scp -r ./build/* username@server_ip:/var/www/your_domain/html The command displays the copied files' names, the progress percentage, and the transfer speed.  Example:  asset-manifest.json 100% 1092 22.0KB/s 00:00favicon.ico 100% 3870 80.5KB/s 00:00index.html 100% 3032 61.1KB/s 00:00logo192.png 100% 5347 59.9KB/s 00:00logo512.png 100% 9664 69.5KB/s 00:00manifest.json 100% 492 10.4KB/s 00:00robots.txt 100% 67 1.0KB/s 00:00main.ab7136cd.chunk.css 100% 943 20.8KB/s 00:00main.ab7136cd.chunk.css.map 100% 1490 31.2KB/s 00:00runtime-main.1caef30b.js.map 100% 12KB 90.3KB/s 00:003.9fbaa076.chunk.js 100% 3561 67.2KB/s 00:002.82f639e7.chunk.js.map 100% 313KB 156.1KB/s 00:02runtime-main.1caef30b.js 100% 2372 45.8KB/s 00:00main.e8c17c7d.chunk.js.map 100% 2436 50.9KB/s 00:003.9fbaa076.chunk.js.map 100% 7690 146.7KB/s 00:002.82f639e7.chunk.js 100% 128KB 226.5KB/s 00:002.82f639e7.chunk.js.LICENSE.txt 100% 1043 21.6KB/s 00:00main.e8c17c7d.chunk.js 100% 1045 21.7KB/s 00:00logo.103b5fa1.svg 100% 2671 56.8KB/s 00:00 Our test project consists of static files, so installing and configuring any compiler on the server is unnecessary. Everything will work with browser functionality. Let's open a browser and enter the IP address of the server or its domain name. If everything works correctly, we should see our app.  Conclusion We reviewed how to auto-deploy a React application to a virtual machine and web hosting, including deploying with an archive. You can try it out on the Hostman servers, separately from your working hosts. It is important to note that we compile on the developer's computer.
06 December 2023 · 8 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