Gérer les événements utilisateur dans React avec TypeScript

Juan Diego Rodriguez 11 décembre 2023
Gérer les événements utilisateur dans React avec TypeScript

Ce tutoriel montrera comment gérer les événements des utilisateurs dans React avec TypeScript en passant une fonction onClick d’un composant à l’autre sur les actions d’un utilisateur.

Gérer les événements utilisateur dans React With TypeScript

Nous utiliserons create-react-app pour démarrer et exécuter rapidement un nouveau projet React.

npx create-react-app my-app --template typescript
cd my-app
npm run start

Après avoir installé les packages nécessaires et démarré le serveur de développement, nous irons dans src/App.tsx, supprimerons tout le code passe-partout et laisserons un composant vide.

import React from "react";

function Message() {
    return <div></div>;
}

export default Message;

Nous allons maintenant ajouter un bouton à la div sur lequel l’utilisateur peut cliquer, et nous répondrons en passant une fonction avec une alerte à l’intérieur de la prop onClick.

function Message() {
    return (
        <div>
            <button
                onClick={() => {
                    alert("I was clicked!");
                }}>
                Click Me!
            </button>
        </div>
    );
}

Rien ne change de Vanilla React à TypeScript, mais les choses sont différentes une fois que nous voulons que la fonction onClick soit transmise en tant que prop du composant Message. Pour le montrer, nous allons créer un autre composant appelé Jeu qui aura Message comme enfant.

function Game() {
    return (
        <div>
            <Message></Message>
        </div>
    );
}

export default Game;

Et nous ferons en sorte que Message reçoive sa fonction onClick et son text comme accessoires provenant de Game.

function Message({onClick, text}) {
    return (
        <div>
            <button onClick={onClick}>{text}</button>
        </div>
    );
}

function Game() {
    return (
        <div>
            <Message
                onClick={() => {
                    alert("I was clicked!");
                }}
                text="Click me!"></Message>
        </div>
    );
}

Cependant, nous obtiendrons les erreurs de compilation suivantes si nous exécutons ce code.

Binding element 'onClick' implicitly has an 'any' type.
Binding element 'text' implicitly has an 'any' type.

Dans JavaScript Vanilla, cela ne provoque pas d’erreur, mais TypeScript en génère une puisque les props onClick et text de Message ont implicitement un type any, c’est-à-dire que nous n’avons pas déclaré quel type ces props devraient boutique. Nous devons créer une interface spécifiant quel type les props du Message doivent avoir pour résoudre ce problème.

interface MessageProps {
    text: string;
    onClick: {};
}

La valeur que le prop text devrait avoir est facile à déclarer puisqu’il ne s’agit que d’une chaîne. Mais la valeur pour onClick est plus difficile.

onClick est plus qu’une fonction normale puisqu’il a une propriété event, et c’est une propriété prédéterminée de l’élément button. Donc, pour définir onClick, nous avons besoin d’une interface prédéfinie fournie avec React, qui dans ce cas s’appelle ButtonHTMLAttributes et contient tous les types de propriétés de l’élément button.

Pour l’utiliser, nous devons étendre l’interface MessageProps pour stocker les types ButtonHTMLAttributes.

interface MessageProps extends ButtonHTMLAttributes {
    text: string;
}

Cependant, cela ne suffit pas, et exécuter le code comme celui-ci générera une erreur puisque l’interface ButtonHTMLAttributes est un Generic Type. Vous pouvez considérer les types génériques comme des interfaces avec des variables, et pour les utiliser, nous les enveloppons autour de <> après avoir déclaré l’interface.

Dans ce cas, l’interface ButtonHTMLAttributes a besoin d’une variable pour savoir quel élément HTML nous utilisons, et ce sera le HTMLButtonElement global.

interface MessageProps extends ButtonHTMLAttributes<HTMLButtonElement> {
    text: string;
}

MessageProps ne contient pas seulement les types des props text et onClick mais les types de toutes les props d’un élément button. Vous pouvez ajouter n’importe quel accessoire d’un “bouton” à Message.

Si vous souhaitez uniquement étendre la propriété onClick, vous n’étendez pas l’interface, créez un nouveau type onClick et affectez la propriété onClick de ButtonHTMLAttributes à l’aide de Types d’accès indexés.

interface MessageProps {
    text: string;
    onClick: ButtonHTMLAttributes<HTMLButtonElement>["onClick"];
}

Pour finir, nous devons déclarer que le composant Message utilisera MessageProps pour ses props de la manière suivante.

function Message({onClick, text}: MessageProps) {
    return (
        <div>
            <button onClick={onClick}>{text}</button>
        </div>
    );
}

Et si nous le voulons, nous pouvons annoter le type de retour comme étant un JSX.Element afin que TypeScript génère une erreur si nous renvoyons accidentellement un autre type.

function Message({onClick, text}: MessageProps): JSX.Element {
    return (
        <div>
            <button onClick={onClick}>{text}</button>
        </div>
    );
}

Et ce serait le résultat final.

import React from "react";
import {ButtonHTMLAttributes} from "react";

interface MessageProps {
    text: string;
    onClick: ButtonHTMLAttributes<HTMLButtonElement>["onClick"];
}

function Message({onClick, text}: MessageProps): JSX.Element {
    return (
        <div>
            <button onClick={onClick}>{text}</button>
        </div>
    );
}

function Game() {
    return (
        <div>
            <Message
                onClick={() => {
                    alert("I was clicked!");
                }}
                text="Click me!"></Message>
        </div>
    );
}

export default Game;

Exemple de code

Juan Diego Rodriguez avatar Juan Diego Rodriguez avatar

Juan Diego Rodríguez (also known as Monknow) is a front-end developer from Venezuela who loves to stay updated with the latest web development trends, making beautiful websites with modern technologies. But also enjoys old-school development and likes building layouts with vanilla HTML and CSS to relax.

LinkedIn