Sign In
Sign In

Deploy a React App

Deploy a React App
Hostman Team
Technical writer
React
06.12.2023
Reading time: 8 min

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: 

  1. Compile React source code with the Node.js functionality.

  2. Clean the hosting from old information.

  3. 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:

  1. 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.

  2. 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/sh
cd /var/www/html/my-app/
npm run-script build
cd /var/www/html/my-app/build/
git init
git 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/sh
nohup /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 file
file_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 correct
if($_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 version
shell_exec("rm -rf $sDir/* $sDir/.[^.]*");
//clone repository with build to the correct directory
shell_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/sh
cd /var/www/html/tilda.local/htdocs/my-app/
npm run-script build
cd build
zip -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 file
file_put_contents(dirname(__FILE__)."/".basename(__FILE__, ".php").".txt", print_r($_SERVER, true).print_r($_FILES, true));
//check tokens
if($_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 directory
shell_exec("rm -rf $sDir/* $sDir/.[^.]*");
//unpack the archive into the directory
shell_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-deploy
Inside 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 start
Happy 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:00
favicon.ico 100% 3870 80.5KB/s 00:00
index.html 100% 3032 61.1KB/s 00:00
logo192.png 100% 5347 59.9KB/s 00:00
logo512.png 100% 9664 69.5KB/s 00:00
manifest.json 100% 492 10.4KB/s 00:00
robots.txt 100% 67 1.0KB/s 00:00
main.ab7136cd.chunk.css 100% 943 20.8KB/s 00:00
main.ab7136cd.chunk.css.map 100% 1490 31.2KB/s 00:00
runtime-main.1caef30b.js.map 100% 12KB 90.3KB/s 00:00
3.9fbaa076.chunk.js 100% 3561 67.2KB/s 00:00
2.82f639e7.chunk.js.map 100% 313KB 156.1KB/s 00:02
runtime-main.1caef30b.js 100% 2372 45.8KB/s 00:00
main.e8c17c7d.chunk.js.map 100% 2436 50.9KB/s 00:00
3.9fbaa076.chunk.js.map 100% 7690 146.7KB/s 00:00
2.82f639e7.chunk.js 100% 128KB 226.5KB/s 00:00
2.82f639e7.chunk.js.LICENSE.txt 100% 1043 21.6KB/s 00:00
main.e8c17c7d.chunk.js 100% 1045 21.7KB/s 00:00
logo.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.

React
06.12.2023
Reading time: 8 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