React - Concepts Avancés

Explorez les fonctionnalités avancées de React pour construire des applications complexes et performantes.

Context API

// Création du contexte
const ThemeContext = React.createContext('light');

// Provider au niveau supérieur
function App() {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Layout />
    </ThemeContext.Provider>
  );
}

// Utilisation du contexte
function Button() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button
      className={`btn-${theme}`}
      onClick={() => setTheme(
        theme === 'light' ? 'dark' : 'light'
      )}
    >
      Changer le thème
    </button>
  );
}

Hooks personnalisés

// Hook pour gérer un formulaire
function useForm(initialState = {}) {
  const [values, setValues] = useState(initialState);

  const handleChange = (e) => {
    const { name, value } = e.target;
    setValues(prev => ({
      ...prev,
      [name]: value
    }));
  };

  const resetForm = () => {
    setValues(initialState);
  };

  return {
    values,
    handleChange,
    resetForm
  };
}

// Utilisation
function LoginForm() {
  const {
    values,
    handleChange,
    resetForm
  } = useForm({
    email: '',
    password: ''
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    // Traiter le formulaire
    resetForm();
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="email"
        value={values.email}
        onChange={handleChange}
      />
      <input
        name="password"
        type="password"
        value={values.password}
        onChange={handleChange}
      />
      <button type="submit">
        Connexion
      </button>
    </form>
  );
}

Gestion d'état avec useReducer

// Définir le reducer
const todoReducer = (state, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return [...state, {
        id: Date.now(),
        text: action.payload,
        completed: false
      }];

    case 'TOGGLE_TODO':
      return state.map(todo =>
        todo.id === action.payload
          ? { ...todo, completed: !todo.completed }
          : todo
      );

    case 'DELETE_TODO':
      return state.filter(
        todo => todo.id !== action.payload
      );

    default:
      return state;
  }
};

// Utilisation dans un composant
function TodoList() {
  const [todos, dispatch] = useReducer(
    todoReducer,
    []
  );

  const addTodo = (text) => {
    dispatch({
      type: 'ADD_TODO',
      payload: text
    });
  };

  return (
    <div>
      <TodoForm onSubmit={addTodo} />
      {todos.map(todo => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={() => dispatch({
            type: 'TOGGLE_TODO',
            payload: todo.id
          })}
          onDelete={() => dispatch({
            type: 'DELETE_TODO',
            payload: todo.id
          })}
        />
      ))}
    </div>
  );
}

Performance et Optimisation

React.memo

const TodoItem = React.memo(({ todo, onToggle }) => (
  <div>
    <input
      type="checkbox"
      checked={todo.completed}
      onChange={onToggle}
    />
    <span>{todo.text}</span>
  </div>
));

// Comparaison personnalisée
const areEqual = (prevProps, nextProps) => {
  return prevProps.todo.id === nextProps.todo.id &&
         prevProps.todo.completed ===
           nextProps.todo.completed;
};

useMemo et useCallback

function TodoList({ todos, filter }) {
  const filteredTodos = useMemo(() =>
    todos.filter(todo =>
      todo.status === filter
    ),
    [todos, filter]
  );

  const handleToggle = useCallback((id) => {
    toggleTodo(id);
  }, []);

  return (
    <div>
      {filteredTodos.map(todo => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={handleToggle}
        />
      ))}
    </div>
  );
}