Starting a React Project in 2024: Best Practices & Tools

Stay ahead in 2024 with the latest tools and best practices for React development. From choosing between JavaScript and TypeScript to leveraging modern build tools like Vite, this guide covers everything you need to know to build efficient, scalable React applications.

Starting a React Project in 2024: Best Practices & Tools

React continues to be a dominant force in front-end development, and staying updated with the latest practices and tools is crucial for building efficient, scalable applications. Whether you’re starting a new project or looking to refresh your React skills, this guide will walk you through the best practices and essential tools you should use in 2024.

React's ecosystem is ever-evolving, and keeping pace with its latest tools and best practices ensures you build high-quality applications. In this post, we’ll explore the most effective ways to set up a React project, to help you create robust and maintainable applications.

1. JavaScript v/s Typescript

When starting a React project, choosing between JavaScript and TypeScript is crucial:

  • JavaScript: Quick setup, flexible, and widely supported. But it has no type safety by default, which can lead to runtime errors and make large projects harder to maintain.
  • TypeScript: Adds static typing, reducing bugs and improving code quality. Better tooling and scalability for large projects. But it has a slightly steeper learning curve, longer setup, and added complexity for smaller projects.
πŸ’­
TypeScript is the right option in my point of view. Because, in the long run it will be very fruitful in the development process. As, it doesn't allow us to write buggy code.

But, if you really want to stick with JavaScript, you can achieve some level of type safety using the prop-types. This is a built-in feature in React that allows you to enforce type-checking on your components' props

2. Choosing a Package Manager

A package manager is a tool you'll rely on throughout the development process to manage your project's dependencies, scripts, and workflows. The right package manager can streamline your development, reduce friction, and ensure consistency across your team.

  • npm: This is the old school default package manager for Node.js, requiring no additional setup. This is the most widely used package manager and hence it has a lot of community support. But, it is getting slower and there are better options.
  • yarn: It is developed by Facebook, is designed to address some of the limitations of npm, the default package manager for Node.js. Yarn is known for its speed, reliability, and additional features that make it a strong contender in the package manager space.
  • pnpm: pnpm uses a unique symlink system, saving disk space by sharing packages across projects. Like Yarn, pnpm offers fast installation times and efficient package management. But requires a little bit of internal knowledge of how things are working under the hood.
πŸ’­
yarn is the best option which is exactly the same as npm with no additional knowledge required. If you are really want to nail this then pnpm is the best as it will save a lot of disk space for you.

3. Bootstraping a React Project

Bootstraping or Scaffolding means getting the initial setup for React. Then we build our Application on this setup. This abstracts away most of the things such bundler setup and gives us a clean starter project. Let's discuss what are the ways of scaffolding a react project.

  • Create React App { CRA }: It is the most popular and straightforward way to bootstrap a React project. Developed by Facebook and is no longer maintained { since 2023 }, CRA provides a powerful and opinionated setup with minimal configuration required. This is not so fast to be honest and has limitations.
// using yarn
yarn create react-app my-app --template typescript

// using npm
npx create-react-app my-app --template typescript
  • Vite: This is better option and probably the best option to start a React Project without using any frameworks { like NextJS, Remix }. This is faster that CRA, and uses ES Build internally.

If you want to know more about this topic, check out this post.

Why you shouldn’t use Create React App in 2024!
Create React App (CRA) has been a popular choice for bootstrapping React applications for several years. It provides a solid starting point with sensible defaults and a straightforward setup process. However, as we move further into 2024, there are several compelling reasons to consider alternatives to CRA. In this blog

4. Essential Development Tools

To maintain high code quality, consistency, and efficiency in your React projects, it’s crucial to set up a few key development tools. These tools help automate tedious tasks, enforce coding standards, and streamline your workflow, ensuring that your codebase remains clean and maintainable.

  • Prettier - Code Formatting
    Ensures that all code follows the same style, regardless of who wrote it. It helps to maintain consistency across the codebase where multiple people are working together.
πŸ’­
Setup Tip: You can configure Prettier to run on every save within your code editor or as part of a pre-commit hook using Husky.
  • ESLint - Code Linting
    It helps in identifying and fixing problems in your JavaScript code. It also helps enforce a consistent style guide and catches potential bugs by analyzing your code for common issues and deviations from best practices.
πŸ’­
Setup Tip: Combine ESLint with Prettier to handle both code style and linting. You can configure ESLint to work alongside Prettier by using plugins like eslint-plugin-prettier.
  • Husky - Git Hooks
    It is a tool that lets you run scripts in your Git hooks, which are actions triggered at specific points in the Git workflow. This is particularly useful for automating tasks like running tests, linting code, or formatting code before commits are made.
πŸ’­
Setup Tip: You can set up a pre-commit hook with Husky that runs ESLint and Prettier before every commit. This ensures that your code is always properly formatted and linted before it enters the codebase.

5. ts/js or tsx/jsx: Choosing the File Extensions

Often, developers default to using .js for all files in a React project, whether they are writing pure functions or React components. However, choosing the correct file extension not only helps organize your code but also ensures that your development environment provides the appropriate tooling and type-checking capabilities.

JS/TS: Pure Functions and Non-React Code

  • JavaScript (.js): Use .js for files that contain pure JavaScript functions or logic that doesn't involve React. These could be utility functions, API handlers, or other business logic.
  • TypeScript (.ts): Similarly, use .ts for TypeScript files that don’t include any React code or JSX syntax. This is ideal for leveraging TypeScript’s type-checking in your pure functions or logic files.

JSX/TSX: React Components

  • JavaScript with JSX (.jsx): Use .jsx for files that include React components written in JavaScript. This extension indicates that the file contains JSX syntax, helping your editor provide the right support and tools.
  • TypeScript with JSX (.tsx): Use .tsx for React components written in TypeScript. This allows you to benefit from TypeScript’s powerful type-checking while working with JSX to define your UI.

It will help organize the codebase. It helps differentiate between pure logic files and those that are React-specific. Next time you make a react project don't just use .js for all the files. Alright ?

6. Choosing a styling framework

Styling your React components is a crucial aspect of building visually appealing and maintainable applications. When it comes to styling in JSX, there are several options available, each with its strengths and best use cases. Let’s explore some of the most popular choices, so you can decide which one best suits your project.

  • Normal CSS
    It is the traditional approach to styling. You write CSS rules in separate .css files and import them into your React components.
    Component:
// Button.jsx
import './Button.css';
const Button = () => <button className="btn">Click Me</button>;
// Button.css
.btn {
  background-color: blue;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
}

This is very familiar to all of you but it's completely a nuisance and It will create conflicting styles because the style is global.

  • CSS with Modules
    It allows you to write CSS with scoped class names, avoiding global conflicts. Each class name is automatically scoped to the component.
// Button.jsx
import styles from './Button.module.css';
const Button = () => <button className={styles.btn}>Click Me</button>;
// Button.module.css
.btn {
  background-color: blue;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
}

This is a better way of writing plain CSS with react, because now we have scoped css and not global.

  • SASS
    It is a CSS preprocessor { another good example is LESS } that adds features like variables, nesting, and mixins. It makes your CSS more powerful and maintainable.
// Button.jsx
import './Button.scss';
const Button = () => <button className="btn">Click Me</button>;
// Button.scss
$btn-bg: blue;
$btn-color: white;

.btn {
  background-color: $btn-bg;
  color: $btn-color;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
}

This is same as CSS but with a lot more features added on top of it. It can have a learning curve

  • Tailwind
    This is my personal favourite way of styling in React. Tailwind CSS is a utility-first CSS framework. It provides predefined classes that you apply directly to your JSX for styling.
// Button.jsx
const Button = () => (
    <button className="bg-blue-500 text-white py-2 px-4 rounded">
        ClickMe
    </button>
);
πŸ’­
Tailwind CSS is my recommendation for rapid development of UI in React. It's fast and have a good community support.

7. UI Frameworks and Libraries

When building user interfaces for React applications, leveraging a UI framework or library can significantly speed up development and ensure a polished, consistent look and feel. Here’s a quick overview of some popular UI frameworks and libraries to consider:

  • Material UI: It is a popular React component library that implements Google’s Material Design system. It provides a comprehensive set of pre-designed components and styles, making it easy to create modern and responsive UIs.
  • ShadCN: It is a newer UI library designed to be lightweight, flexible, and modern. It emphasizes simplicity and developer experience, providing a clean and customizable set of components.
πŸ’­
shadCN is my top recommendation for achieving a clean and modern UI. It offers a diverse set of components that are incredibly useful for building sophisticated and stylish interfaces.

8. State Management

Basically, there are two kinds of states in a React Application.

  • Client State: refers to the data that is managed and maintained within the client-side application, typically using React’s state management tools. This includes UI-related data like form inputs, toggle states, or local component state.
πŸ’­
Redux Toolkit is my recommendation for handling Client Side states.
  • Server State: pertains to the data that originates from an external server and needs to be synchronized with the client-side application. This state is typically fetched from APIs or other data sources and often requires managing loading states, error handling, and synchronization.
πŸ’­
Tanstack Query is my recommendation for handling Server side states.

9. Handling HTTP Requests

When working with data fetching and server communication in React, you typically use one of two approaches: Axios or the built-in Fetch API. Here’s a brief overview of each:

  • Axios is a popular JavaScript library for making HTTP requests. It simplifies the process of sending requests and handling responses, and it comes with several useful features out of the box. It is promise-based and also has interceptors which is an useful feature in some scenarios.
import axios from 'axios';

const fetchData = async () => {
  try {
    const response = await axios.get('https://api.example.com/data');
    console.log(response.data);
  } catch (error) {
    console.error('Error fetching data:', error);
  }
};
  • Fetch API is a built-in JavaScript API for making HTTP requests. It provides a simple way to perform network requests and handle responses directly within JavaScript.
const fetchData = async () => {
  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) throw new Error('Network response was not ok');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Error fetching data:', error);
  }
};
πŸ’­
Axios is my recommendation for handling HTTP requests. It makes a lot of things easier to handle and makes the development process more intuitive with its client feature.

10. Testing Libraries

When it comes to testing React applications, you generally use different tools for different types of tests. Jest and Cypress are two popular choices, each serving distinct purposes:

  • Jest
    It is a widely-used JavaScript testing framework primarily for unit testing. It is designed to ensure that individual components or functions work as expected.
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

test('renders the component', () => {
  render(<MyComponent />);
  expect(screen.getByText('Hello World')).toBeInTheDocument();
});
  • Cypress
    It is an end-to-end testing framework designed for integration testing. It focuses on testing the entire application flow, from the user interface down to the back-end.
describe('MyComponent', () => {
  it('should display the correct text', () => {
    cy.visit('/my-component');
    cy.contains('Hello World').should('be.visible');
  });
});
πŸ’­
Combine Jest for unit testing and Cypress for end-to-end testing to ensure comprehensive coverage and confidence in your application. This approach covers both isolated components and full application flows, addressing various edge cases effectively.

11. Directory Structure

Having a clean directory structure is important for the scaling and maintainability of the code. Ofcourse, you don't want to find in which file and where you had written a function { search feature can help, still it's important }.

my-react-app/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ pages/
β”‚   β”œβ”€β”€ queries/
β”‚   β”œβ”€β”€ stores/
β”‚   β”œβ”€β”€ services/
β”‚   β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ styles/
β”‚   β”œβ”€β”€ types/
β”‚   β”œβ”€β”€ tests/
β”‚   β”‚   β”œβ”€β”€ unit/
β”‚   β”‚   └── e2e/
β”‚   β”œβ”€β”€ App.tsx
β”‚   β”œβ”€β”€ index.tsx
β”‚   └── tsconfig.json
β”œβ”€β”€ .eslintrc.js
β”œβ”€β”€ .prettierrc
β”œβ”€β”€ .husky/
β”‚   β”œβ”€β”€ pre-commit
β”œβ”€β”€ package.json
└── yarn.lock

The above directory structure will give you a comprehensive structure for organizing different files and logic in your React application.

Whooof! That was quite a long blog. Isn't it? Well, I think if you have reached this far, it will be worth it for you. You have gained a lot of useful information that will also be fruitful in your next project and career.

That's it for today, I hope you find it useful. Stay subscribed to get the latest updates.


Your Name

Smruti Ranjan Badatya

Full Stack Developer @eLitmus

LinkedIn LinkedIn