0% found this document useful (0 votes)
29 views

React Architecture Patterns for Your Projects

Uploaded by

jocelynnsa
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views

React Architecture Patterns for Your Projects

Uploaded by

jocelynnsa
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 24

React Architecture Patterns

for Your Projects

Learn what are the best practices when structuring your


React.JS projects

Aman Mittal
·
Follow
·

1.2K

6
React is an un-opinionated framework in the front-end

ecosystem. Its versatile nature does not provide a way

to organize and structure a web application. The way

an application is organized and structured is how a

developer or a team of developers interact with it. A

project with no logical structure means that everyone

can do whatever they want inside it. A well-structured

project requires developers to think deeper about

their implementation and at the same time keep

things organized. It also makes the codebase easy to

navigate, modify and scale to add new features.


The architecture of a project is essential. An

organized codebase is how a team of developers gets

productive within the given structure in the long run.

In this article, let’s look at some of the ways to keep

the lifecycle of a React application healthy and well

organized and what patterns you can follow.

Navigating a Directory Structure


Always have a starting point in your React

application. This starting point comprises various

folders such as assets, components, services, utils

(reusable utility functions), pages, etc. Each of these

folders contains various files required to fulfill the

directory’s purpose.

For example, a bare minimum React project created

using the create-react-app command-line utility to

create a new React app comes with a /src directory.

The starting point of this default React app (index.js


file) is situated in this directory. A common practice is

to use the /src directory as a familiar convention. That

means all the different folders for components, pages,

etc., are created inside this directory.

Using this convention, the top-level directory

structure where your React app’s codebase lives can

be viewed as:

└── /src

├── /assets

├── /components

├── /context

├── /hooks

├── /pages

├── /services
├── /utils

└── App.js

├── index.js

The important part here is not to make the directory

name a hard and fast rule but to follow a neat

organization that anyone in the codebase can

understand. That means, depending on the directory

names you like to follow, the /services directory can be

called /api.

Common Modules
One advantage of React being un-opinionated is it

doesn’t care how you divide your modules. When

developing a page in a React app, consider dividing it

into modular pieces. This will help you reduce the

complexity and create structures that are open for

reusable or shared across the application.


Shareable code in React app should be divided under

its own domain. A common module can be reusable

custom components, custom hooks, business logic,

constants, and utility functions. These reusable pieces

are shared across the application to be used on more

than one page component. Having a folder for them in

your application’s directory structure is a good

starting point.

Add Custom Components in their own folders


Examples of reusable components can be buttons,

input fields, and content containers like cards. All of

these components live within the /components directory.

Each component will live inside its own sub-directory.

For example, if you are creating reusable Buttons,

here is an example of a directory structure you can

consider:

└── /src
├── /components

| ├── /Button

| | ├── Button.js

| | ├── Button.styles.js

| | ├── Button.test.js

| | ├── Button.stories.js

| ├──index.js

Here is a brief explanation of what each file inside the

Button directory contains:

● Button.js file that contains the actual React

component

● Button.styles.js file, let’s assume you are using

styled components, contains corresponding

styles
● Button.test.js file that contains tests

● Button.stories.js the Storybook file

In the above structure, also notice that there is an

index.js file located in the /components directory. In this

scenario, this file acts as an index of all components

that are part of the namesake directory. This file will

look like the following:

// /src/components/index.js

import { Button } from './Button/Button';

import { InputField } from './InputField/InputField';

import { Card } from './Card/Card';

export { Button, Card, InputField };

Create Custom Hooks


A reusable React Hook is like a reusable working

part. Just like you create custom components,

creating a custom hook can help reduce code

complexity.

Consider an example. In your React app, you have

two different pages representing a login and a signup

form. Each of these pages contains text input fields

where users can enter their credentials and submit

the form using a button. One of the input fields used

in both forms is for users to enter their password. The

password field contains an icon that allows the app

user to toggle between the field’s visibility. Suppose

you write the same code to implement this behavior

in both login and signup forms. In that case, you will

be duplicating the code.


A solution to this problem is to create a custom hook

to toggle the icon and the field’s visibility based on

the icon. Here is an example of a custom hook:

// /src/hooks/useTogglePasswordVisibility/index.js

export const useTogglePasswordVisibility = () => {

const [passwordVisibility, setPasswordVisibility] =


useState(true);

const [rightIcon, setRightIcon] = useState('eye');

const handlePasswordVisibility = () => {

if (rightIcon === 'eye') {

setRightIcon('eye-off');

setPasswordVisibility(!passwordVisibility);
} else if (rightIcon === 'eye-off') {

setRightIcon('eye');

setPasswordVisibility(!passwordVisibility);

};

return {

passwordVisibility,

rightIcon,

handlePasswordVisibility

};
};

The custom hook above starts with a use naming

convention. Even though React isn’t strict about

naming conventions, it is important to follow them in

this scenario. This hook also handles its own state and

method and can be re-used on a password field,

whether inside the login or a signup form.

The /hooks directory structure can be similar to

components where a reusable hook lives inside their

subdirectories:

└── /src

├── /hooks

| ├── /useTogglePasswordVisibility

| | ├── index.js
| | ├── useTogglePasswordVisibility.test.js

| ├──index.js

Use Absolute Imports


By default, a React app that uses the before

mentioned directory structure might lead you to use

import paths in the following manner:

// some file

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

You can configure your React application by adding

support for importing modules using absolute paths.

In a plain React app, this can be done by creating and

configuring a jsconfig.json file at the root of your

project.

Here is an example of a simple configuration inside

the jsconfig.json file:


{

"compilerOptions": {

"baseUrl": "src"

},

"include": ["src"]

It makes it a lot easier to import components within

the project and also, at the same time moving files

without the need to change the import statements. If

you want to import a module located at /src/components,

you can import it as follows:

import { Button } from 'components';

If you have a custom Webpack configuration inside a

file called webpack.config.js. In that case, you can


customize this further to use a prefix like @components

or ~components.

module.exports = {

resolve: {

extensions: ['js'],

alias: {

'@': path.resolve(__dirname, 'src'),

'@components': path.resolve(__dirname,
'src/components')

'@hooks': path.resolve(__dirname, 'src/hooks'),

};
This will allow you to import using a prefix. For

example, a module located at /src/components/Button can

be imported as:

import { Button } from '@components';

Note: If you’re using TypeScript, you will have a file

called tsconfig.json. You can configure this file. For

more information, check out Create React App

documentation here.

Open Source Session Replay


Debugging a web application in production may be

challenging and time-consuming. OpenReplay is an

Open-source alternative to FullStory, LogRocket and

Hotjar. It allows you to monitor and replay everything

your users do and shows how your app behaves for

every issue. It’s like having your browser’s inspector

open while looking over your user’s shoulder.


OpenReplay is the only open-source alternative

currently available.

Happy debugging, for modern frontend teams — Start

monitoring your web app for free.

Separate business logic from UI


The /pages directory will contain the UI for most of the

application and the structure of each page in the form

of React components. These components are naturally

coupled with the business logic they represent. It is a


common behavior that you will find in any React

application. However, avoid unnecessary complexity

in a UI component, you can separate the business

logic from it.

One way to separate the UI and the logic is to create

a custom hook, for example, for making an API

request. Here is an example of making an API request

to get items from an endpoint:

import { useQuery } from 'react-query';

export const moviesApi = {

nowPlaying: () =>

fetch(`${BASE_URL}/movie/now_playing?api_key=$
{API_KEY}&page=1`).then(res =>

res.json()
)

};

export const useNowPlayingMovies = () => {

const { isLoading: nowPlayingLoading, data:


nowPlayingData } = useQuery(

['movies', 'nowPlaying'],

moviesApi.nowPlaying

);

return {

nowPlayingLoading,

nowPlayingData
};

};

In the above snippet, take note that the API request to

fetch data from the endpoint /movie/now_playing

happens in two parts. The first part is the API request

itself using JavaScript’s fetch method that gets the

data in JSON format. The second part is where the

useQuery hook from React Query library is configured

and wrapped inside a custom hook.

You can store or create this custom hook file inside

the dedicated /hooks directory or create another

directory for API-related hooks such as /api or

/services.

The Utils directory


Having a utils directory is completely optional. If your

application tends to have some global utility


functions, it could be a good idea to separate them

from the UI components. A /utils directory may

contain app-wide constants and helper methods. For

example, more than one UI component in your

application may require some validation logic.

Separating this validation business logic in its own

file under the /utils directory will help you create

separate flows.

Avoiding creating a single Context for


everything
Usually, when you pass props from a parent to a child

component, it can be as simple as passing them from

one to another. However, the complexity arises when

there are many components in between. This creates

an inconvenient way to pass props.

React Context provides a way to pass data through

the component tree without prop drilling. It is an


alternative approach that lets a parent component

provide props to the entire tree below it. This way,

sharing data becomes easy, and one can avoid

passing unnecessary props.

In your React application, you should have separate

Contexts for different things. For example, your React

app uses themes for UI components, but some of

these components use internationalization or i18n.

The i18n context doesn’t care if the theme exposes a

certain dark or light mode value. In this scenario, you

will have two different context providers. This helps

you separate data logically.

const App = () => {

return (

<ThemeProvider>
<QueryClientProvider>

<Routes />

</QueryClientProvider>

</ThemeProvider>

Also, if a Context is used in one of the components,

you do not need to wrap the application’s root with

that Context’s provider. If a section of the application

doesn’t require specific data, you don’t have to share

it.

Conclusion
Patterns or practices described in this article are

based on one’s experience. They may not work for

every large-scale application of every kind. Take the


parts that resonate with you or you think will help you

get things more organized in your React project and

leave out the rest. The important part when it comes

to organizing a React app is to structure it in a

manner that makes sense to you, and if you happen to

work in a team with other people, it should make

sense to them too.

Originally published at https://blog.openreplay.com

on December 22, 2021.

You might also like