Skip to content

React

Vue d'ensemble

React est une bibliothèque JavaScript pour construire des interfaces utilisateur interactives, basée sur des composants réutilisables et un rendu efficace via le Virtual DOM.

Avantages clés

  • Component-based : Architecture modulaire
  • Virtual DOM : Performance optimale
  • Hooks : Gestion d'état moderne
  • Ecosystem : Next.js, Gatsby, Create React App

Composants modernes

// Functional Component avec Hooks
import { useState, useEffect } from 'react';

const UserList = () => {
    const [users, setUsers] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        fetchUsers();
    }, []);

    const fetchUsers = async () => {
        try {
            setLoading(true);
            const response = await fetch('/api/users');
            if (!response.ok) throw new Error('Failed to fetch');
            const data = await response.json();
            setUsers(data.data);
        } catch (err) {
            setError(err.message);
        } finally {
            setLoading(false);
        }
    };

    if (loading) return <div>Loading...</div>;
    if (error) return <div>Error: {error}</div>;

    return (
        <div className="user-list">
            {users.map(user => (
                <UserCard key={user.id} user={user} />
            ))}
        </div>
    );
};

const UserCard = ({ user }) => (
    <div className="user-card">
        <h3>{user.name}</h3>
        <p>{user.email}</p>
        <span>{user.posts_count} posts</span>
    </div>
);

Custom Hooks

// Custom hook pour API
const useApi = (url) => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        const fetchData = async () => {
            try {
                setLoading(true);
                const response = await fetch(url);
                const result = await response.json();
                setData(result);
            } catch (err) {
                setError(err);
            } finally {
                setLoading(false);
            }
        };

        fetchData();
    }, [url]);

    return { data, loading, error };
};

// Utilisation
const Dashboard = () => {
    const { data: users, loading } = useApi('/api/users');

    return (
        <div>
            {loading ? <Spinner /> : <UserList users={users} />}
        </div>
    );
};

Integration avec Laravel

// Service API pour Laravel backend
class ApiService {
    constructor(baseURL = '/api') {
        this.baseURL = baseURL;
        this.token = localStorage.getItem('auth_token');
    }

    async request(endpoint, options = {}) {
        const url = `${this.baseURL}${endpoint}`;
        const config = {
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                ...(this.token && { 'Authorization': `Bearer ${this.token}` }),
            },
            ...options,
        };

        const response = await fetch(url, config);

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        return response.json();
    }

    // CRUD operations
    async getUsers(page = 1) {
        return this.request(`/users?page=${page}`);
    }

    async createUser(userData) {
        return this.request('/users', {
            method: 'POST',
            body: JSON.stringify(userData),
        });
    }

    async updateUser(id, userData) {
        return this.request(`/users/${id}`, {
            method: 'PUT',
            body: JSON.stringify(userData),
        });
    }

    async deleteUser(id) {
        return this.request(`/users/${id}`, {
            method: 'DELETE',
        });
    }
}

export default new ApiService();

Testing avec Jest

// UserCard.test.jsx
import { render, screen } from '@testing-library/react';
import UserCard from './UserCard';

describe('UserCard', () => {
    const mockUser = {
        id: 1,
        name: 'John Doe',
        email: 'john@example.com',
        posts_count: 5
    };

    it('renders user information correctly', () => {
        render(<UserCard user={mockUser} />);

        expect(screen.getByText('John Doe')).toBeInTheDocument();
        expect(screen.getByText('john@example.com')).toBeInTheDocument();
        expect(screen.getByText('5 posts')).toBeInTheDocument();
    });

    it('handles missing posts count', () => {
        const userWithoutPosts = { ...mockUser, posts_count: 0 };
        render(<UserCard user={userWithoutPosts} />);

        expect(screen.getByText('0 posts')).toBeInTheDocument();
    });
});

Ressources