8.1 KiB
Notre premier composant React
Si vous êtes arrivé ici, c'est que vous avez compris ce qu'est un composant React et qu'il est composant de props
et d'un state
.
Mettons donc en pratique ce que vous avez vu.
Voici le cahier de charge fonctionnel du composant à implémenter :
Fonction:
- On veut ajouter un bouton
Home
dans l'éditeur pour revenir au menu principal
Contraintes principales :
- Le bouton
home
ne doit pas rafraîchir la page
Contraites secondaires :
- Le bouton est positionné en bas sur la barre
- Le bouton change de couleur à chaque fois que le curseur entre dedans
- Le bouton possède un icône home
Initialiser un composant
Commençont par créer le composant sans le lier forcément au reste du projet.
Par convention comme il est dit dans la section Pour commencer, créons le fichier Home.tsx
dans un dossier Home/
dans src/Components
. Il est recommandé de toujours créer un dossier pour le composant pour plus tard si on veut ajouter des styles propres au composant ou si on veut faire des tests.
Maintenant créons le squelette du composant. Pour rappel, on utilise la syntaxe fonctionnelle (i.e. une fonction = un composant).
// Home.tsx
export function Home(): JSX.Element {
return <></>;
}
Note: vous pouvez utiliser le snippet tsrfc
si vous utilisez l'extension de VSCode.
La convention de nommage indique qu'il faut prioriser les fonctions nommées (donc pas de flèches fonctions).
Mettons le bouton html et mettons du texte dedans :
export function Home(): JSX.Element {
return (
<button>
Home
</button>
);
}
Appeler une fonction
Pour que le bouton appelle une fonction nous allons utiliser la propriété onClick
. Pour lui équiper d'une variable/fonction, on la met entre accolades prop={var}
.
function GoHome(): void {
location.reload();
}
export function Home(): JSX.Element {
return (
<button
onClick={GoHome}
>
Home
</button>
);
}
Cela devrait être suffisant pour revenir au menu principal. Appelons-le dans l'editeur.
Ajouter le composant dans l'editeur
Tout ce qui est UI doit se mettre dans UI.tsx
.
On sait que l'on doit l'ajouter dans la barre à gauche, soit Bar.tsx
Commençons par importer le composant dans Bar.tsx
:
// Bar.tsx
import { Home } from '../Home/Home';
...
Puis ajoutons-le dans la vue :
// Bar.tsx
export function Bar(props: IBarProps): JSX.Element {
return (
<div className='bar'>
...
<Home />
</div>
);
}
Testez avec pnpm dev
. Et ouvrez la page sur http://localhost:5173
.
Et voilà ! Vous avez fini !
...
Sauf que vous n'avez respecté aucune des contraintes.
Faisons mieux. Utilisons les props
et le state
de l'application.
Props et state
Le composant doit restaurer l'état du menu principal.
Dans le menu principal, lorsque l'on clique sur Start from scratch
, le composant doit forcément changer un état pour cacher le menu.
Ce que l'on veut faire est donc de renverser cette opération, autrement dit changer l'état qui permet de cacher le menu pour le remontrer.
Allons donc dans le composant MainMenu.tsx
et analysons le contenu du bouton Start from scratch
.
// MainMenu.tsx
...
default:
return (
<div className='absolute bg-blue-50 p-12 rounded-lg drop-shadow-lg grid grid-cols-1 md:grid-cols-2 gap-8 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
<button type="button" className='mainmenu-btn' onClick={() => {
setWindowState(WindowState.Loading);
props.newEditor();
}}>Start from scratch</button>
<button type="button" className='mainmenu-btn' onClick={() => setWindowState(WindowState.Load)}>Load a configuration file</button>
</div>
);
On trouve la fonction onClick
suivante :
// MainMenu.tsx
{
setWindowState(WindowState.Loading);
props.newEditor();
}
Aha! On trouve une fonction qui change d'état. Cependant ! On découvre aussi qu'elle appelle une fonction newEditor
.
Instinctivement, vu que l'on cherche une fonction qui permet de changer d'état, on pourrait croire que c'est setWindowState
qui gère mais on va vite comprendre que ce n'est pas elle.
Pour rappel setWindowState
est un setteur d'état, et qu'elle est définie dans le composant. Autrement dit, elle ne gère pas l'état de l'application. De plus, un indice indique que le l'état du menu passe de Main
à Loading
. Elle ne fait donc que changer sa propre vue pour passer à celle d'une animation de loading que l'on peut voir plus haut dans le switch
.
newEditor
étant une fonction donnée par props
, doit donc correspondre à la fonctionalité que l'on veut renveser.
Regardons donc le composant parent de MainMenu
: App
.
// App.tsx
...
<MainMenu
newEditor={() => NewEditor(
setEditorState, setLoaded
)}
loadEditor={(files: FileList | null) => LoadEditor(
files,
setEditorState,
setLoaded
)}
/>
...
Cette fonction newEditor
appelle donc une autre fonction NewEditor
.
export function NewEditor(
setEditorState: Dispatch<SetStateAction<IEditorState>>,
setLoaded: Dispatch<SetStateAction<boolean>>
): void {
// Fetch the configuration from the API
FetchConfiguration()
.then((configuration: IConfiguration) => {
// Set the editor from the given properties of the API
const editorState: IEditorState = GetDefaultEditorState(configuration);
setEditorState(editorState);
setLoaded(true);
}, (error) => {
console.debug('[NewEditor] Could not fetch resource from API. Using default.', error);
setLoaded(true);
});
}
Cette fonction à l'air assez compliquée, mais on sait qu'elle utilise setEditorState
et setLoaded
. Et c'est tout ce qui nous intéresse.
Donc pour renverser l'état de App
il faut appeler soit setEditorState
ou soit setLoaded
. En analysant un peu plus près App.tsx
, on remarque l'évidante condition permettant d'afficher ou non le menu principal :
// App.tsx
...
if (isLoaded) {
return (
<div>
<Editor
(...)
/>
</div>
);
}
return (
<div className='mainmenu-bg'>
<MainMenu
(...)
/>
</div>
Ainsi, on sait qu'il faut juste appeler setLoaded
le setteur d'état de isLoaded
:
// App.tsx
const [isLoaded, setLoaded] = useState<boolean>(false);
Cependant comment appeler cette fonction depuis Home
? Et bien nous allons utiliser les props
pour passer la fonction en dessous.
Comme pour MainMenu
, dans Home.tsx
nous allons mettre la fonction GoHome
dans les props :
import React from 'react';
interface IHomeProps {
goHome: () => void
}
export function Home({ goHome }: IHomeProps): JSX.Element {
return (
<button
onClick={goHome}
>
Home
</button>
);
}
Note: vous pouvez utiliser Home(props: IHomeProps)
et appeler props.goHome
comme tout le reste du projet, mais le destructuring d'objet est autorisé.
Home est utilisé dans les composants Bar, UI, et Editor avant d'être appelé dans App. Il faut faire la même chose, ajouter la fonction dans les props et l'appeler dans le composant :
// Bar.tsx
interface IBarProps {
goHome: () => void
}
...
export function Bar(props: IBarProps): JSX.Element {
return (
<div className='bar'>
...
<Home
goHome={props.goHome}
/>
</div>
);
}
Faites la même chose pour UI et Editor.
Enfin dans App.tsx
, créez la fonction permettant de changer isLoaded
vers false
:
...
if (isLoaded) {
return (
<div>
<Editor
root={props.root}
configuration={editorState.configuration}
history={editorState.history}
historyCurrentStep={editorState.historyCurrentStep}
goHome={() => {
setLoaded(false);
}}
/>
</div>
);
}
...
Félicitation vous avez correctement développé votre premier composant Home !
Essayons maintenant de faire le reste dans le prochain chapitre avec TailwindCSS