Building Modern Applications with React
A complete guide to building high-performance, maintainable web applications with React.
InSkillCoach
Building Modern Applications with React
React is one of the most popular JavaScript libraries for building user interfaces. Developed and maintained by Facebook (Meta), it lets you build complex web applications with reusable components and efficient state management.
Why Choose React?
- Declarative approach: You describe what your UI should look like, and React takes care of the updates
- Component-based: Build encapsulated, reusable interface elements
- Rich ecosystem: A wide range of complementary libraries and tools
- Large community: Support, resources, and regular updates
- Optimized performance: Virtual DOM and reconciliation for efficient updates
- Adopted by major companies: Facebook, Instagram, Netflix, Airbnb, and more
Setting Up a React Project
Creating a Project with Create React App
Create React App is an official tool for quickly getting started with a React project:
# Installation
npx create-react-app mon-application
# Démarrage
cd mon-application
npm start
Using Vite (a Modern Alternative)
Vite offers faster build times and a better development experience:
# Installation
npm create vite@latest mon-application -- --template react
# Démarrage
cd mon-application
npm install
npm run dev
React Fundamentals
Components
Components are the basic building blocks of a React application:
// Function component
function Salutation(props) {
return <h1>Bonjour, {props.nom} !</h1>;
}
// Usage
<Salutation nom="Alice" />
JSX
JSX is a syntax extension that lets you write HTML inside JavaScript:
const element = <h1>Bonjour, monde !</h1>;
// With JavaScript expressions
const nom = "Alice";
const element = <h1>Bonjour, {nom} !</h1>;
// With attributes
const element = <img src={user.avatarUrl} alt="Avatar" />;
// Nested elements
const element = (
<div>
<h1>Titre</h1>
<p>Paragraphe</p>
</div>
);
Props
Props let you pass data from a parent component to a child component:
// Component definition
function Carte(props) {
return (
<div className="carte">
<h2>{props.titre}</h2>
<p>{props.description}</p>
{props.children}
</div>
);
}
// Usage
<Carte
titre="Mon titre"
description="Ma description"
>
<button>En savoir plus</button>
</Carte>
State
State lets you store data that can change over time:
import { useState } from 'react';
function Compteur() {
// State declaration
const [compteur, setCompteur] = useState(0);
return (
<div>
<p>Vous avez cliqué {compteur} fois</p>
<button onClick={() => setCompteur(compteur + 1)}>
Cliquez ici
</button>
</div>
);
}
Lifecycle with Hooks
Hooks let you use state and other React features in function components:
import { useState, useEffect } from 'react';
function ExempleEffet() {
const [compteur, setCompteur] = useState(0);
// Similar to componentDidMount and componentDidUpdate
useEffect(() => {
// Update the document title
document.title = `Vous avez cliqué ${compteur} fois`;
// Cleanup function (similar to componentWillUnmount)
return () => {
document.title = 'React App';
};
}, [compteur]); // Runs only if compteur changes
return (
<div>
<p>Vous avez cliqué {compteur} fois</p>
<button onClick={() => setCompteur(compteur + 1)}>
Cliquez ici
</button>
</div>
);
}
Event Handling
React uses an HTML-like syntax to handle events:
function Bouton() {
function handleClick(e) {
e.preventDefault();
console.log('Le bouton a été cliqué');
}
return (
<button onClick={handleClick}>
Cliquez ici
</button>
);
}
Conditional Rendering
You can display different elements depending on conditions:
function Connexion(props) {
const estConnecte = props.estConnecte;
return (
<div>
{estConnecte ? (
<BoutonDeconnexion />
) : (
<BoutonConnexion />
)}
</div>
);
}
// Another approach
function Message(props) {
const nonLu = props.messagesNonLus.length;
return (
<div>
<h1>Bonjour !</h1>
{nonLu > 0 && (
<p>Vous avez {nonLu} message(s) non lu(s).</p>
)}
</div>
);
}
Lists and Keys
To render lists of elements, use map() and unique keys:
function ListeArticles(props) {
const articles = props.articles;
return (
<ul>
{articles.map((article) => (
<li key={article.id}>
{article.titre}
</li>
))}
</ul>
);
}
Advanced State Management
Context API
The Context API lets you share data between components without passing props down manually:
// Context creation
const ThemeContext = React.createContext('light');
// Context provider
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
// Consuming the context with useContext
function Bouton() {
const theme = useContext(ThemeContext);
return (
<button className={theme}>
Je suis stylisé selon le thème {theme}
</button>
);
}
useReducer for Complex State Management
useReducer is preferable to useState for complex state:
import { useReducer } from 'react';
// Reducer definition
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { compteur: state.compteur + 1 };
case 'decrement':
return { compteur: state.compteur - 1 };
default:
throw new Error();
}
}
function Compteur() {
// Using the reducer
const [state, dispatch] = useReducer(reducer, { compteur: 0 });
return (
<div>
Compteur: {state.compteur}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}
State Management Libraries
For more complex applications, you can use dedicated libraries:
Redux
// Actions
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
// Action creators
function increment() {
return { type: INCREMENT };
}
// Reducer
function compteurReducer(state = { valeur: 0 }, action) {
switch (action.type) {
case INCREMENT:
return { valeur: state.valeur + 1 };
case DECREMENT:
return { valeur: state.valeur - 1 };
default:
return state;
}
}
// Store
const store = createStore(compteurReducer);
// Connected component
function Compteur({ valeur, increment, decrement }) {
return (
<div>
<span>{valeur}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
const mapStateToProps = state => ({
valeur: state.valeur
});
const mapDispatchToProps = {
increment,
decrement
};
export default connect(mapStateToProps, mapDispatchToProps)(Compteur);
Zustand (a Modern Alternative)
import create from 'zustand';
// Store creation
const useStore = create(set => ({
compteur: 0,
increment: () => set(state => ({ compteur: state.compteur + 1 })),
decrement: () => set(state => ({ compteur: state.compteur - 1 })),
}));
// Usage in a component
function Compteur() {
const { compteur, increment, decrement } = useStore();
return (
<div>
<span>{compteur}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
Routing with React Router
React Router lets you handle navigation in a React application:
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Accueil</Link>
<Link to="/a-propos">À propos</Link>
<Link to="/contact">Contact</Link>
</nav>
<Routes>
<Route path="/" element={<Accueil />} />
<Route path="/a-propos" element={<APropos />} />
<Route path="/contact" element={<Contact />} />
<Route path="/produits/:id" element={<DetailProduit />} />
<Route path="*" element={<PageNonTrouvee />} />
</Routes>
</BrowserRouter>
);
}
// Accessing URL parameters
import { useParams } from 'react-router-dom';
function DetailProduit() {
const { id } = useParams();
return <h1>Détail du produit {id}</h1>;
}
Forms in React
Controlled Forms
In a controlled form, React manages the form state:
import { useState } from 'react';
function FormulaireConnexion() {
const [email, setEmail] = useState('');
const [motDePasse, setMotDePasse] = useState('');
function handleSubmit(e) {
e.preventDefault();
console.log('Email:', email);
console.log('Mot de passe:', motDePasse);
}
return (
<form onSubmit={handleSubmit}>
<div>
<label>
Email:
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</label>
</div>
<div>
<label>
Mot de passe:
<input
type="password"
value={motDePasse}
onChange={(e) => setMotDePasse(e.target.value)}
required
/>
</label>
</div>
<button type="submit">Se connecter</button>
</form>
);
}
Form Libraries
For complex forms, use libraries such as Formik or React Hook Form:
// With React Hook Form
import { useForm } from 'react-hook-form';
function FormulaireInscription() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>Nom</label>
<input {...register('nom', { required: 'Le nom est requis' })} />
{errors.nom && <p>{errors.nom.message}</p>}
</div>
<div>
<label>Email</label>
<input
{...register('email', {
required: 'L\'email est requis',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Adresse email invalide'
}
})}
/>
{errors.email && <p>{errors.email.message}</p>}
</div>
<button type="submit">S'inscrire</button>
</form>
);
}
Performance Optimization
React.memo
React.memo lets you avoid unnecessary re-renders of function components:
const MonComposant = React.memo(function MonComposant(props) {
// Your component
});
useMemo and useCallback
These hooks let you memoize values and functions:
import { useMemo, useCallback } from 'react';
function ExempleOptimisation({ a, b }) {
// Memoizes the result of the computation
const resultat = useMemo(() => {
console.log('Calcul coûteux...');
return a * b;
}, [a, b]); // Recomputes only if a or b changes
// Memoizes the function
const handleClick = useCallback(() => {
console.log('Bouton cliqué avec résultat:', resultat);
}, [resultat]); // Recreated only if resultat changes
return (
<div>
<p>Résultat: {resultat}</p>
<button onClick={handleClick}>Cliquer</button>
</div>
);
}
Lazy Loading
Lazy loading lets you split your application into smaller chunks:
import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
// Lazy loading of components
const Accueil = lazy(() => import('./pages/Accueil'));
const APropos = lazy(() => import('./pages/APropos'));
const Contact = lazy(() => import('./pages/Contact'));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<div>Chargement...</div>}>
<Routes>
<Route path="/" element={<Accueil />} />
<Route path="/a-propos" element={<APropos />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
Testing in React
Unit Tests with Jest and React Testing Library
// Component to test
function Salutation({ nom }) {
return <h1>Bonjour, {nom} !</h1>;
}
// Test
import { render, screen } from '@testing-library/react';
import Salutation from './Salutation';
test('affiche le message de salutation', () => {
render(<Salutation nom="Alice" />);
const element = screen.getByText(/bonjour, alice !/i);
expect(element).toBeInTheDocument();
});
Interaction Tests
import { render, screen, fireEvent } from '@testing-library/react';
import Compteur from './Compteur';
test('incrémente le compteur lorsque le bouton est cliqué', () => {
render(<Compteur />);
// Check the initial value
expect(screen.getByText(/compteur: 0/i)).toBeInTheDocument();
// Click the button
fireEvent.click(screen.getByText('+'));
// Check the new value
expect(screen.getByText(/compteur: 1/i)).toBeInTheDocument();
});
Deploying a React Application
Production Build
# With Create React App
npm run build
# With Vite
npm run build
Static Hosting
You can deploy your application to platforms such as:
- Netlify: Drag and drop the
buildfolder or set up continuous deployment - Vercel: Optimized for React applications, with automatic deployment from GitHub
- GitHub Pages: Ideal for personal or open-source projects
- Firebase Hosting: A complete solution with authentication and a database
Best Practices
- Structure your project: Organize your files by feature or by type
- Use function components: Simpler and more performant with Hooks
- Avoid prop drilling: Use Context or a state management library
- Write tests: Make sure your application works as expected
- Optimize performance: Use React.memo, useMemo, and useCallback judiciously
- Follow SOLID principles: Build components with a single responsibility
- Use TypeScript: Add static typing to prevent errors
- Document your components: Use tools like Storybook
Conclusion
React is a powerful library for building modern, high-performance user interfaces. Its flexibility and rich ecosystem make it an excellent choice for developing web applications of all sizes.
By mastering the core concepts and best practices covered in this article, you’ll be able to build React applications that are robust, maintainable, and scalable.
About InSkillCoach
Training and technology expert
Coach specializing in advanced technologies and AI, backed by GNeurone Inc.
Certifications:
- AWS Certified Solutions Architect – Professional
- Google Cloud certifications
- Microsoft Certified: DevOps Engineer Expert
- Certified Kubernetes Administrator (CKA)
- CompTIA Security+
Comments
Comments are powered by GitHub Discussions
Sign in with GitHub to join the discussion