How to Set Up React Project

How to Set Up a React Project React has become one of the most widely adopted JavaScript libraries for building modern, interactive user interfaces. Developed and maintained by Facebook (now Meta), React enables developers to create reusable UI components that render dynamically based on changing data. Whether you're building a simple landing page or a complex single-page application (SPA), settin

Oct 30, 2025 - 13:08
Oct 30, 2025 - 13:08
 0

How to Set Up a React Project

React has become one of the most widely adopted JavaScript libraries for building modern, interactive user interfaces. Developed and maintained by Facebook (now Meta), React enables developers to create reusable UI components that render dynamically based on changing data. Whether you're building a simple landing page or a complex single-page application (SPA), setting up a React project correctly from the start is critical to ensuring scalability, performance, and maintainability.

Many developers new to React face challenges during the initial setup—confusion over tooling choices, outdated documentation, or misconfigured environments. This guide provides a comprehensive, step-by-step walkthrough to set up a React project using the latest industry-standard practices. You’ll learn not only how to get started, but also how to structure your project for long-term success, optimize performance, and leverage powerful tools that streamline development.

By the end of this tutorial, you’ll have a fully functional React project ready for development, with a solid foundation that adheres to best practices and modern web standards.

Step-by-Step Guide

Prerequisites

Before you begin setting up your React project, ensure your development environment meets the following requirements:

  • Node.js (version 18 or higher recommended)
  • npm (Node Package Manager) or yarn (optional but recommended)
  • A code editor (e.g., Visual Studio Code)
  • A modern web browser (Chrome, Firefox, or Edge)

You can verify your Node.js and npm installations by opening your terminal or command prompt and running:

node -v

npm -v

If these commands return version numbers (e.g., v18.17.0 and 9.6.7), you’re ready to proceed. If not, download and install the latest LTS version of Node.js from nodejs.org. The installer includes npm automatically.

Option 1: Using Create React App (CRA) – The Traditional Approach

Create React App (CRA) was the official and most popular way to bootstrap a React application for years. Although it’s now in maintenance mode, it remains a reliable option for beginners due to its zero-configuration setup.

To create a new React project with CRA, run the following command in your terminal:

npx create-react-app my-react-app

This command:

  • Creates a new directory named my-react-app
  • Installs all necessary dependencies (React, ReactDOM, Webpack, Babel, etc.)
  • Sets up a development server with hot module replacement (HMR)
  • Configures ESLint and Prettier for code quality
  • Generates a basic project structure with sample files

Once the installation completes, navigate into the project folder:

cd my-react-app

Start the development server:

npm start

Your browser will automatically open to http://localhost:3000, displaying the default React welcome page. You’re now running a fully functional React application.

Option 2: Using Vite – The Modern, Faster Alternative

While CRA is still functional, the React community has largely shifted toward Vite—a next-generation frontend tooling platform that offers significantly faster development server startup and hot module replacement. Vite leverages native ES modules and pre-bundling for speed, making it the preferred choice for new projects as of 2024.

To create a React project with Vite, run:

npm create vite@latest my-react-app -- --template react

You’ll be prompted to choose a variant:

  • React – Standard React with JavaScript
  • React TypeScript – React with TypeScript support

For this guide, select React (JavaScript). If you're comfortable with TypeScript or plan to use it in production, choose the TypeScript option—it’s strongly recommended for larger applications.

After the project is created, navigate into the directory:

cd my-react-app

Install dependencies:

npm install

Start the development server:

npm run dev

Vite will launch a server, typically on http://localhost:5173. You’ll see a clean, minimal React interface with a counter example.

Why Choose Vite Over CRA?

While both tools work, Vite offers several advantages:

  • Faster cold start: Vite starts the dev server in milliseconds, not seconds.
  • Native ES modules: No need for complex bundling during development.
  • Better performance: Optimized for modern browsers and builds.
  • Flexible configuration: Easy to extend with plugins and custom configs.
  • Active development: Vite is continuously updated; CRA is in maintenance mode.

For new projects, Vite is the recommended choice. CRA is still viable for learning or legacy projects, but new developers should adopt Vite to stay current with industry trends.

Project Structure Overview

After setting up your project with Vite or CRA, you’ll see a standard directory structure. Here’s what you’ll typically find:

my-react-app/

├── public/

│ └── index.html

├── src/

│ ├── assets/

│ ├── components/

│ ├── App.jsx

│ ├── main.jsx

│ └── index.css

├── package.json

├── vite.config.js (or webpack.config.js if using CRA)

├── .gitignore

└── README.md

Key Files Explained:

  • public/index.html – The HTML template where React renders your app. The root <div id="root"></div> is where React injects the component tree.
  • src/main.jsx – The entry point of your application. It imports React and ReactDOM and renders the App component.
  • src/App.jsx – The root component of your app. This is where you’ll build your component hierarchy.
  • src/components/ – A folder for reusable UI components (e.g., Button, Header, Navbar).
  • src/assets/ – Stores images, icons, fonts, and other static files.
  • package.json – Contains project metadata, scripts, and dependencies.
  • vite.config.js – Configuration file for Vite (e.g., plugins, aliases, server settings).

As your project grows, you’ll want to organize components further into folders like pages/, hooks/, services/, and contexts/. We’ll cover structure best practices in the next section.

Understanding JSX and Component Rendering

React uses JSX—a syntax extension that looks like HTML but is actually JavaScript. JSX allows you to write HTML-like code directly in your JavaScript files. For example:

function App() {

return <div>

<h1>Welcome to React!</h1>

<p>This is my first React component.</p>

</div>;

}

Notice that JSX must return a single root element. If you need multiple top-level elements, wrap them in a fragment:

function App() {

return <>

<h1>Title</h1>

<p>Content</p>

</>;

}

React components can be written as functions (functional components) or classes (class components). Functional components are now the standard due to their simplicity and compatibility with React Hooks.

The App component is rendered into the DOM by main.jsx:

import React from 'react'

import ReactDOM from 'react-dom/client'

import App from './App'

import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(

<React.StrictMode>

<App />

</React.StrictMode>

)

React.StrictMode is a development tool that helps identify potential problems in your app by activating additional checks and warnings. It does not affect production builds.

Running and Building for Production

To test your app during development, use:

npm run dev

When you’re ready to deploy your application, generate an optimized production build:

npm run build

This command creates a dist/ folder (or build/ in CRA) containing minified, bundled JavaScript, CSS, and HTML files ready for deployment to any static hosting service (e.g., Netlify, Vercel, GitHub Pages, or an S3 bucket).

You can preview the production build locally by installing a static server:

npm install -g serve

serve -s dist

Then visit http://localhost:5000 to see your app as it will appear in production.

Best Practices

Component Architecture and File Organization

A well-organized project structure improves maintainability, collaboration, and scalability. Avoid dumping all components into a single src/components folder. Instead, adopt a feature-based or domain-driven structure:

src/
├── components/           

Reusable UI primitives (Button, Input, Card)

│ ├── Button/

│ │ ├── Button.jsx

│ │ └── Button.module.css

│ └── Header/

│ ├── Header.jsx

│ └── Header.css ├── pages/

Route-specific components (Home, About, Contact)

│ ├── Home/

│ │ ├── Home.jsx

│ │ └── Home.module.css

│ └── About/

│ └── About.jsx ├── hooks/

Custom React hooks (useAuth, useLocalStorage)

├── contexts/

React Context providers (AuthContext, ThemeContext)

├── services/

API calls and data fetching (apiClient.js, userService.js)

├── utils/

Helper functions (formatDate, validateEmail)

├── assets/

Images, icons, fonts

├── styles/

Global CSS, themes, variables

├── App.jsx

└── main.jsx

This structure separates concerns: UI components are reusable, page components are route-bound, and services handle data logic. It also makes it easy to locate files and test components in isolation.

Use Functional Components and Hooks

Class components are deprecated in modern React development. Always use functional components with React Hooks such as:

  • useState() – for managing local state
  • useEffect() – for side effects (API calls, subscriptions, DOM manipulation)
  • useContext() – for accessing context values
  • useMemo() and useCallback() – for performance optimization

Example of a counter component using hooks:

import React, { useState } from 'react';

function Counter() {

const [count, setCount] = useState(0);

return (

<div>

<p>Count: {count}</p>

<button onClick={() => setCount(count + 1)}>Increment</button>

</div>

);

}

export default Counter;

Code Splitting and Lazy Loading

As your app grows, bundle size becomes a performance bottleneck. Use React’s lazy() and Suspense to load components only when needed:

import { lazy, Suspense } from 'react';

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./pages/Home'));

const About = lazy(() => import('./pages/About'));

function App() {

return (

<Router>

<Suspense fallback="<div>Loading...</div>">

<Routes>

<Route path="/" element="<Home />" />

<Route path="/about" element="<About />" />

</Routes>

</Suspense>

</Router>

);

}

This reduces initial load time and improves user experience, especially on mobile networks.

State Management

For small to medium applications, React’s built-in state management (useState, useContext) is sufficient. Avoid premature optimization with external libraries like Redux unless you have complex state logic across multiple components.

If you need global state management, consider:

  • React Context API – for simple global state (theme, user auth)
  • Zustand – lightweight, fast, and easy to use alternative to Redux
  • Redux Toolkit – for large-scale apps with complex state logic

For most projects, start with Context and upgrade only when necessary.

Styling Best Practices

There are many ways to style React components. Here are the recommended approaches:

  • CSS Modules – Scoped styles with automatic class naming (e.g., Button.module.css)
  • Styled-components – CSS-in-JS for dynamic styling
  • Tailwind CSS – Utility-first framework for rapid UI development
  • Global CSS – Only for reset styles or typography

For new projects, we recommend Tailwind CSS due to its speed, customization, and component-friendly syntax. Install it via:

npm install -D tailwindcss postcss autoprefixer

npx tailwindcss init -p

Then configure tailwind.config.js:

module.exports = {

content: [

"./index.html",

"./src/**/*.{js,jsx,ts,tsx}",

],

theme: {

extend: {},

},

plugins: [],

}

Add Tailwind to your src/index.css:

@tailwind base;

@tailwind components;

@tailwind utilities;

Now you can use utility classes directly in JSX:

<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">

Click me

</button>

Code Quality and Linting

Enforce consistent code style and catch errors early with ESLint and Prettier. Vite projects come with these preconfigured, but if you’re using CRA or another setup, install them manually:

npm install --save-dev eslint prettier eslint-plugin-react eslint-config-prettier

Create .eslintrc.json:

{

"extends": [

"eslint:recommended",

"plugin:react/recommended",

"prettier"

],

"plugins": ["react"],

"parserOptions": {

"ecmaVersion": 2021,

"sourceType": "module",

"ecmaFeatures": {

"jsx": true

}

},

"env": {

"browser": true,

"es2021": true

},

"rules": {

"react/react-in-jsx-scope": "off"

}

}

Create .prettierrc:

{

"semi": true,

"trailingComma": "es5",

"singleQuote": true,

"printWidth": 80,

"tabWidth": 2

}

Add a script to your package.json to auto-format:

"scripts": {

"format": "prettier --write .",

"lint": "eslint src"

}

Environment Variables

Use environment variables to manage configuration across environments (development, staging, production). Vite exposes variables prefixed with VITE_.

Create a .env file in your project root:

VITE_API_URL=https://api.example.com

VITE_APP_NAME=My React App

Access them in your code:

const apiUrl = import.meta.env.VITE_API_URL;

Never expose sensitive keys (e.g., API secrets) in client-side code. Use server-side proxies or environment variables on the backend for such data.

Tools and Resources

Essential Development Tools

  • Visual Studio Code – The most popular code editor with excellent React support via extensions.
  • React Developer Tools – Browser extension for Chrome and Firefox to inspect React component trees, state, and props.
  • ESLint – Identifies problematic patterns and enforces code quality.
  • Prettier – Automatically formats code to maintain consistency.
  • React Router – Declarative routing for React applications. Install via npm install react-router-dom.
  • React Query – Powerful data fetching and caching library. Superior to manual fetch() or Axios for complex state management.
  • Storybook – Isolated component development environment. Great for design systems and component testing.
  • Jest + React Testing Library – Industry-standard tools for unit and integration testing React components.

Recommended Libraries

Depending on your project needs, consider integrating these libraries:

  • Formik or React Hook Form – For form handling and validation.
  • Axios – HTTP client for making API requests (alternative to native fetch).
  • Chart.js or Recharts – For data visualization.
  • React Icons – Library of popular icon sets (Feather, FontAwesome, Material Icons).
  • React Hook Form – Lightweight, performant form library with built-in validation.

Learning Resources

Deployment Platforms

Once your project is built, deploy it to one of these platforms:

  • Vercel – Optimized for React and Next.js. Free tier available. One-click deploy from GitHub.
  • Netlify – Excellent for static sites. Supports forms, serverless functions, and custom domains.
  • GitHub Pages – Free hosting for public repositories. Requires minor configuration for React apps.
  • Render – Supports static sites and Node.js backends. Simple UI and generous free tier.
  • Amazon S3 + CloudFront – For enterprise-grade hosting with global CDN.

Real Examples

Example 1: Simple Todo List App

Here’s a minimal but complete example of a React Todo app using Vite and functional components:

src/components/TodoItem.jsx

import React from 'react';

function TodoItem({ todo, onDelete, onToggle }) {

return (

<li className="flex items-center justify-between p-3 border-b hover:bg-gray-50">

<span

className={todo.completed ? "line-through text-gray-500" : ""}

onClick={onToggle}

>

{todo.text}

</span>

<button

className="text-red-500 hover:text-red-700"

onClick={onDelete}

>

Delete

</button>

</li>

);

}

export default TodoItem;

src/components/TodoForm.jsx

import React, { useState } from 'react';

function TodoForm({ onAdd }) {

const [text, setText] = useState('');

const handleSubmit = (e) => {

e.preventDefault();

if (text.trim()) {

onAdd({ id: Date.now(), text, completed: false });

setText('');

}

};

return (

<form onSubmit={handleSubmit} className="mb-6">

<input

type="text"

value={text}

onChange={(e) => setText(e.target.value)}

placeholder="Add a new task..."

className="px-4 py-2 border rounded-l w-3/4"

autoFocus

/>

<button

type="submit"

className="bg-blue-500 text-white px-4 py-2 rounded-r"

>

Add

</button>

</form>

);

}

export default TodoForm;

src/App.jsx

import React, { useState } from 'react';

import TodoForm from './components/TodoForm';

import TodoItem from './components/TodoItem';

function App() {

const [todos, setTodos] = useState([]);

const handleAdd = (todo) => {

setTodos([...todos, todo]);

};

const handleDelete = (id) => {

setTodos(todos.filter(todo => todo.id !== id));

};

const handleToggle = (id) => {

setTodos(

todos.map(todo =>

todo.id === id ? { ...todo, completed: !todo.completed } : todo

)

);

};

return (

<div className="max-w-md mx-auto p-6">

<h1 className="text-2xl font-bold mb-4">My Todo List</h1>

<TodoForm onAdd={handleAdd} />

<ul>

{todos.map(todo => (

<TodoItem

key={todo.id}

todo={todo}

onDelete={() => handleDelete(todo.id)}

onToggle={() => handleToggle(todo.id)}

/>

))}

</ul>

</div>

);

}

export default App;

This example demonstrates core React concepts: state management, event handling, component composition, and conditional rendering—all in under 100 lines of code.

Example 2: API Integration with React Query

Instead of manually using fetch(), use React Query to manage data fetching, caching, and loading states:

import { useQuery } from '@tanstack/react-query';

import axios from 'axios';

const fetchPosts = async () => {

const response = await axios.get('https://jsonplaceholder.typicode.com/posts');

return response.data;

};

function PostList() {

const { data, error, isLoading } = useQuery(['posts'], fetchPosts);

if (isLoading) return <p>Loading...</p>;

if (error) return <p>Error: {error.message}</p>;

return (

<ul>

{data.map(post => (

<li key={post.id}>{post.title}</li>

))}

</ul>

);

}

React Query automatically caches responses, handles retries, and provides loading/error states—reducing boilerplate and improving UX.

FAQs

Can I use React without Node.js?

No. React requires a build step (transpilation, bundling, minification) that relies on Node.js and tools like Vite or Webpack. However, once built, the output files (HTML, JS, CSS) can be served from any static server without Node.js.

Do I need to learn JavaScript before React?

Yes. React is a JavaScript library. You should be comfortable with ES6+ features like arrow functions, destructuring, modules, promises, and async/await. If you’re new to JavaScript, start with free resources like MDN Web Docs or JavaScript.info before diving into React.

Is React only for frontend development?

React is primarily a frontend UI library, but it can be used on the server with Next.js (React’s framework) for server-side rendering (SSR) and static site generation (SSG). It can also be used with React Native to build mobile apps.

What’s the difference between React and React Native?

React is for building web applications using HTML and CSS. React Native is a framework that uses React syntax to build native mobile apps (iOS and Android) using platform-specific components instead of web elements.

How do I update React to the latest version?

Run npm update react react-dom. Always check the official React documentation for breaking changes before upgrading. Use npm outdated to see which packages need updates.

Should I use TypeScript with React?

Yes. TypeScript adds static typing, which improves code quality, reduces bugs, and enhances developer experience—especially in large teams. Vite supports TypeScript out of the box. Start with the react-ts template.

How do I add routing to my React app?

Install React Router DOM: npm install react-router-dom. Then use <Routes> and <Route> components to define navigation paths. Example:

<Routes>

<Route path="/" element="<Home />" />

<Route path="/about" element="<About />" />

</Routes>

How do I test React components?

Use React Testing Library with Jest. Install them with:

npm install --save-dev @testing-library/react @testing-library/jest-dom jest

Write a simple test for a component:

import { render, screen } from '@testing-library/react';

import App from './App';

test('renders learn react link', () => {

render(<App />);

const linkElement = screen.getByText(/learn react/i);

expect(linkElement).toBeInTheDocument();

});

Can I use React with other frameworks like Angular or Vue?

Technically, yes—React can be embedded into other frameworks as a component. However, it’s not recommended. Choose one primary framework per project to avoid complexity, performance overhead, and maintenance issues.

What should I do if my React app is slow?

Use React DevTools to profile component re-renders. Optimize with React.memo, useMemo, and useCallback. Code-split with lazy(). Minimize bundle size by removing unused dependencies. Use a CDN for static assets. Analyze bundle with source-map-explorer.

Conclusion

Setting up a React project is more than just running a single command—it’s about laying the foundation for a scalable, maintainable, and high-performing application. Whether you choose Vite or CRA, the key is to follow modern best practices from day one: organize your code logically, use functional components and hooks, leverage tools like ESLint and Prettier, and structure your state and data fetching efficiently.

By adopting Vite as your build tool, integrating Tailwind CSS for styling, and using React Query for data management, you position your project to thrive in today’s fast-paced development environment. Don’t rush into complex state libraries or over-engineer your architecture—start simple, and evolve as your needs grow.

Remember: React is not just a library—it’s an ecosystem. Master the fundamentals, explore the tools, and stay curious. The React community is vast and supportive, and with the right setup, you’re ready to build anything from a personal portfolio to a production-grade enterprise application.

Now that you’ve set up your project, the next step is to start building. Create your first component. Connect it to an API. Add a route. Deploy it. The journey of a thousand lines of code begins with a single npm create vite.