React.js Architecture Pattern: Implementation + Best Practices

Read it in 13 Mins

Last updated on
25th Nov, 2022
Published
10th Sep, 2022
Views
7,574
React.js Architecture Pattern: Implementation + Best Practices

React comes with so many features that help you develop fantastic User Interfaces. One cool thing with React is that it doesn't force you to use a predefined architectural pattern like other JavaScript frameworks do. That is to say, React allows you to determine the structure of your application by yourself. An architectural pattern in front-end development is the blueprint of the User Interface. Becoming an in-demand frontend developer is now easier, check out our online web development certificate courses. You can go through this article to get better clarity on React Architecture's best practices. 

What is React Architecture? 

React architecture is a collection of components responsible for building a software’s User Interface (UI). You can also see it as an organization of your codebase that helps you build your unique project. 

For example, a React architecture will include several UI components such as buttons, forms, API services, Central State Management services, etc. 

Because of this ReactJs architectural freedom, it is the most preferred JavaScript library (framework) for building front-end applications. Get to know more about React.js features. 

How Does React Architecture Help in Web Development 

The following are some of the ways React architecture helps in web development: 

  • React assists you in developing a component-based software architecture that simplifies maintenance and code reuse. 
  • It enables you to maintain a global state variable by utilizing state management libraries such as Redux. 
  • Because React architecture allows you to build out components, code expansion becomes much easier as your project grows. 
  • Since it is component-based, the React architecture makes unit testing much easier. 

Know more about React.js state. 

Steps to Implement React Architecture Pattern

Every React project has an architectural representation that is tailored to the project's purpose and dependencies. A React Web3 project, for example, will not have the same architecture as a React PWA project. However, when getting started with React, we recommend following the structure below which includes: 

  • Project Directory  
  • src 
  • Assets 
  • Components 
  • Services 
  • Store 
  • Utils 
  • Views  

Navigating a Directory Structure

Using the example below, a React project has a source (src) folder where all the essential files and folders are listed: 

└── /src 

  ├── /assets 

  ├── /components 

  ├── /views 

  ├── /services 

  ├── /utils 

  ├── /hooks 

  ├── /store 

  └── App.js 

  ├── index.js 

  ├── index.css 

  • The assets folder contains all of the project's static files, such as your logo, fonts, images, and favicons. 
  • Components folder contains a bit collection of UI codes such as buttons, forms, avatars, and so on. 
  • The views folder contains all your React application's web pages. 
  • Services folder contains code that allows you to interact with external API resources. 
  • The utils folder contains reusable function snippets for performing quick tasks like text truncation or down casing. 
  • Hooks folder contains codes and logic that can be reused across multiple components. 
  • The store folder houses your state management files, such as Redux, which are used to make certain functions and variables available throughout your application. 
  • The main component of your React application is the App.js file. This file connects all components and views. 
  • Index.js file is the React application's entry point. It is responsible for bootstrapping the React library and mounting it on the root element. 
  • index.css is the main and global CSS file for our application. Any writing style to this file will apply throughout the project.  

Common Modules

Because React is a non-opinionated framework, it doesn't care how you divide your modules when building your application. But what exactly are modules? They are bundled reusable sets of functions, classes, and components that aid in the software development process. 

React assists you in reducing complexity and creating open, reusable, and shared structures across your application. Common modules include reusable custom components, custom hooks, business logic, constants, and utility functions. 

These modules, which are shared throughout your software, can be used in a variety of components, views, and even projects. 

Add Custom Components in Folders

Below is an example of a React custom input component. In your components directory, create a new folder called Input. Now, within this input folder create the files represented below: 

└── /src 

  ├── /components 

  | ├── /Input 

  | | ├── Input.js 

  | | ├── Input.css 

  | | ├── Input.test.js

  • Input.js is the JavaScript file for writing all the logic for this component. 
  • The Input.css contains all the styles for this Input component. 
  • Input.test.js contains all the test cases for this component. 

Next, you will then have to create an index.js file in the components directory to bundle up the components. See the code below for example: 

// /src/components/index.js 
import { Button } from './Button/Button'; 
import { Input } from './Input/Input'; 
import { Card } from './Card/Card'; 
export { Button, Card, Input }; 

With this file set up, you can then use it on any view or pages in your project. 

Create Custom Hooks 

A custom Hook is a function that begins with "use" and may invoke other Hooks. Understanding this definition will help you use custom hooks effectively. Creating a custom hook is essential for reducing code complexity. 

For example, let’s say that you have two distinct pages in your React app called a Login and Registration page. Each of these pages has input fields where visitors may enter their information and submit at the click of a button. If you want a password visibility toggling feature as part of the password field in both the pages, you may have to duplicate your code. 

To reduce duplications and complexities from your codebase, writing a custom hook that toggles the password's visibility is the right approach. Here's an example of a custom hook:  

Create a hook as described in the code snippet below: 

└── /src 
  ├── /hooks 
      ├──usePasswordToggler.js 

Paste the codes below into the usePasswordToggler file and save. 

// ./src/hooks/usePasswordToggler.js 
import {useState} from 'react'; 
export const usePasswordToggler = () => { 
  const [passwordVisibility, setPasswordVisibility] = useState(true); 
  const [type, setType] = useState('password'); 
  const handlePasswordVisibility = () => { 
    if (type === 'password') { 
      setType('text'); 
      setPasswordVisibility(!passwordVisibility); 
    } else if (type === 'text') { 
      setType('password'); 
      setPasswordVisibility(!passwordVisibility); 
    } 
  }; 
  return { 
    type, 
    passwordVisibility, 
    handlePasswordVisibility 
  }; 
}; 

The above custom hooks are used to create a state of a hook with three objects it returns: 

  • type: This returns a form type, either text or password. 
  • passwordVisibility: This returns a boolean value indicating whether the password is hidden or visible. 
  • handlePasswordVisibility: This is a function that toggles the above state variables of type and passwordVisibility either to show or hide. 

Next, you can use this hook in your regular React component, see the example below: 

import React from 'react'; 
import { usePasswordToggler } from './hooks/usePasswordToggler'; 
import './App.css';  
function App() { 
  const { type, passwordVisibility, handlePasswordVisibility } = usePasswordToggler() 
  return ( 
    <main> 
      <div> 
        <input type={type} placeholder='Enter password...' /> 
        <button onClick={handlePasswordVisibility}>{passwordVisibility ? 'Show' : 'Hide'} Password</button> 
      </div> 
    </main> 
  ); 
} 

export default App; 

The above codes will produce the following outputs: 

And that is how to create and utilize a React custom hook. 

Use Absolute Imports

By default, React apps with nested directory structures might lead to confusion on the import path such as the example below: 

// some file 
import { Button } from '../../components'; 

You can resolve a potential confusion on the directory paths by adding support for importing modules using absolute paths to your React application.  

A rule can be added to the jsconfig.json file at the root of your project to resolve confusions with your folder paths. But what is jsconfig.json file? It's a configuration file that helps your editor's Language Server Protocol understand the JavaScript in your project folder. 

Here is an example within the jsconfig.json file which can improve your directory path: 

{ 
 "compilerOptions": { 
    "baseUrl": "src" 
 }, 
 "include": ["src"] 
} 

Now, with this modification, you can import components located at  /src/components this way: 

import { Button } from 'components'; 

If your project includes webpack.config.js at the root, you may further personalize it by using a prefix such

as @components or ~components. See the configuration below: 

module.exports = { 
 resolve: { 
  extensions: ['js'], 
  alias: { 
   '@': path.resolve(__dirname, 'src'), 
   '@components': path.resolve(__dirname, 'src/components') 
   '@hooks': path.resolve(__dirname, 'src/hooks'), 
  } 
 } 
}; 

With the above configurations, still using the previous example, you can now set absolute path for your component as follows: 

import { Button } from '@components'; 

Isn’t that a lot cleaner? 

Open Source Session Replay 

The ability to review exactly what happens in someone else's browser but at a later time is referred to as session replay. It's not a recorded screen capture because that wouldn't allow you to play with the details, inspect the dev tools, or see what JavaScript errors appeared that were invisible to the user. I'm referring to a direct replay of the real DOM changing second by second. 

There are various session replay tools available, but the one we'll be discussing today is OpenReplay. Why OpenReplay specifically? Because it provides a fully functional open-source version that you can download and install.  

Another reason why OpenReplay is highly recommended is because of its ease of use. For example, by signing up, you'll be given a JavaScript snippet to include in your code. It works similarly to Google Analytic's snippet in that you copy and paste it there and it just works. 

The image below shows a session replay recording being reproduced from an application user interface. 

Separate business logic from UI 

To improve the quality of your codes and make maintenance a lot easier, it is highly recommended that you separate logic from the UI components. The user interface structure of each page should be stored in the /pages or /views directory as React components.  

As previously discussed, one of the patterns to distinguish the UI structure from the business logic is to build a custom hook. Here is an example of an app that retrieves users from an endpoint, to separate the logic from the UI, we created a file in the services folder >> api.js and pasted the codes below: 

import axios from 'axios';
const api = { 
    fetchUsers: async () => { 
      const URL = 'https://jsonplaceholder.typicode.com/users'; 
      return await axios.get(URL) 
        .then((res) => res) 
        .catch((err) => err) 
    } 
} 
export default api; 

The above code takes care of the business logic, now let’s hook up the user interface with the code below: 

import './App.css' 
import api from './services/api' 
import { useState } from 'react' 
function App() { 
  const [users, setUsers] = useState([]) 
 const getUsers = () => { 
    api 
      .fetchUsers() 
      .then((res) => setUsers(res.data)) 
  } 
  return ( 
    <main> 
      <div> 
        <pre className="api__result">{ JSON.stringify(users, null, 2) }</pre> 
        <button onClick={getUsers}>Get Users</button> 
        <button onClick={() => setUsers([])}>Clear</button> 
      </div> 
    </main> 
  ); 
}
export default App; 

And this is how the output looks like: 

 

And that is how you simply separate business logic from the view (UI). 

The Utils Directory 

Utils folder as previously explained contains some helper functions to be used across your application. It is not required though, but for maintaining the rules of clean coding, it is recommended that you include it in your application. For example, here is how you would package a utility function. 

Let’s create a file utils >> helper.js and paste the codes below inside of it: 

const fileName = 'Helper' 
const truncate = (str, num) => { 
  if (str.length > num) { 
    return str.slice(0, num) + "..."; 
  } else { 
    return str; 
  } 
} 
const navigateTo = (route) => { 
  window.location.href = route; 
} 
const genStr = () => { 
  return (Math.random() + 1).toString(36).substring(2); 
} 
export { 
  fileName, 
  truncate, 
  navigateTo, 
  genStr 
} 

With the above codes, you can then import and use them in your respective projects: 

Avoiding Creating a Single Context for Everything 

One of the most common problems in a React app is figuring out how to share state across multiple components. 

The complexity emerges when there are several components in between the parent and a child component. This results in an awkward situation called passing props. 

React Context allows you to transmit data via the component tree without prop drilling, which is actually a method that allows a parent component to offer props to the whole tree of children underneath it. Sharing data becomes easier using this method eliminating the need to pass props. 

Your React project should have various Contexts for accomplishing different tasks. You are not required to disclose data if a component of the application doesn’t require it. For example, your theme context should not contain codes for your API context and should only wrap the child components that will have a need for Theme state. See the example below: 

const App = () => { 
  return (   
  <ThemeProvider> 
    <QueryClientProvider> 
      <Routes /> 
    </QueryClientProvider> 
  </ThemeProvider> 
  ) 
} 

React Architecture Diagram for building large Web Applications  

The above image describes a React architecture for building a large web application. This architecture uses React libraries such as Redux Saga which is a middleware that allows your store to interact asynchronously with resources outside of itself. It also uses Axios for accessing API resources on external servers such as on AWS (amazon web services). 

 Here are some of the reasons why the architecture is suited for creating large React apps:  

  • Consistent Global State - The React architecture provides a Central State Management repository for the application, improving data communication between multiple components. 
  • Increased Scalability - The architecture makes interactions with backend services more efficient and expandable. 
  • Improved Testability -The component-based nature of React architecture makes testing easier. 
  • Decoupled Components - By design, React architecture employs a component-based approach to software development. Componentizing an application into parts decouples it and makes it easier to maintain. 

React Architecture Best Practices 

The following are some general guidelines for creating a scalable and optimized React application: 

  • Avoid using an excessive number of nested files and directories, and don't overthink on the application structure. 
  • Don't move files around; you can't afford to change file locations when a team of developers is working on the same project. 
  • As the number of components in your React project grows, be intentional about your naming conventions. Facebook's codebase contains over 30,000 React components, which they keep up-to-date by following well-defined component naming standards. 
  • Separate your features into separate reducers, with each one exporting its action creators and selectors, so that teams can work on them more effectively. 
  • Use Redux-saga in your project to manage a large amount of asynchronous code and side effects. 

And there you have it for the best practices for ReactJs architecture patterns. 

Conclusion  

As always, it has been fun dishing out this much information to you, hope you got a ton of value from this tutorial. 

If you want to speed up your software development career, kindly check out React.js syllabus KnowledgeHut.

Frequently Asked Questions (FAQs) 

1. What is the architecture of ReactJs?

React architecture is a collection of components and software modules that helps you as a developer build an application’s user interface (UI). 

2. What is the best architecture for React? 

The best architecture for ReactJs is dependent on the purpose and size of the application. However, it is recommended that your React architecture has components, views, hooks, utils, and store folders. 

3. Is React component-based architecture?

Yes, it is, a React application can be segmented into components and later combined to form the overall interface of your app. 

4. What design pattern does React use?

ReactJS uses HOC pattern, which stands for higher-order-component. It is an advanced design that allows us to reuse component codes across an application. HOC pattern is perfect for features that require component logic to be shared across our application. 

Profile

Darlington Gospel

Blog Author

I am a Software Engineer skilled in JavaScript and Blockchain development. You can reach me on LinkedIn, Facebook, Github, or on my website.