1829 views
TP React === ## Objectif de ce TP - Comprendre la notion de composant en ReactJS, - Utilisation de typescript pour structurer vos développements - Comprendre le fonctionnement basique du routeur de react ## Initialisation du projet ```bash npm install -g npx npx create-react-app tpreact --template typescript cd tpreact code . # Pour compiler le projet et lancer le serveur npm run start ``` ## Anatomie du projet généré Le projet généré contient principalement un composant **App**. Il est instancié dans le fichier *index.tsx* ```tsx ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); ``` Le code de ce composant **App** est le suivant. ```tsx import React from 'react'; import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.tsx</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); } export default App; ``` Nous pouvons bien sur le simplifier de la façon suivante. ```tsx import React from 'react'; import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> </div> ); } export default App; ``` Il est important de comprendre qu'il y a deux sortes de composants en react. - **Functional Components** Les composants sans états ou fonctionnels peuvent être définis en TypeScript de cette manière : ```tsx import * as React from 'react'; const Count: React.FunctionComponent<{ count: number; }> = (props) => { return <h1>{props.count}</h1>; }; export default Count; ``` Pour définir un composant fonctionnel nous utilisons **React.FunctionComponent** et définissons la structure de l'objet et ses proprités attendues. Dans ce scénario, nous nous attendons à ce qu'une seule propritété, nommée *count*, soit passée et nous la définissons en ligne. Nous pouvons également définir cela d'autres manières, en créant une interface telle que Props ```tsx interface Props { count: number; } const Count: React.FunctionComponent<Props> = (props) => { return <h1>{props.count}</h1>; }; ``` Ce débat entre composant fonctionnel ou composant défini sous forme de classes ne semble pas trancher. Pour ma part, j'apprécie de définir des composants sous forme de classes. - **Class Components** Les composants définis à l'aide de classe peuvent également être définis en tant que tels dans TypeScript. Ces composants ont un état interne, cet état eut évoluer. ```tsx import * as React from 'react'; import Count from './Count'; interface Props {} interface State { count: number; }; export default class Counter extends React.Component<Props, State> { state: State = { count: 0 }; increment = () => { this.setState((state, props) => ({ counter: state.count + 1 })); }; decrement = () => { this.setState((state, props) => ({ counter: state.count -1 1 })); }; render () { return ( <div> <Count count={this.state.count} /> <button onClick={this.increment}>Increment</button> <button onClick={this.decrement}>Decrement</button> </div> ); } } ``` :warning: Il est important de ne pas modifier le state directement mais passer par la fonction de callback pour récupérer l'état du state précédent. Voir https://en.reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous > **Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.** Merci @Arnaud Delourmel pour la correction Nous pouvons également définir des defaultProps dans un composant. Nous pouvons mettre à jour notre exemple de compteur de la manière suivante : ```tsx import * as React from 'react'; interface Props { count?: number; } export default class Count extends React.Component<Props> { static defaultProps: Props = { count: 10 }; render () { return <h1>{this.props.count}</h1>; } } ``` Dans ce cas là, nous arréterons aussi de passer *this.state.count* au composant **Counter**, car cela écraserait notre accessoire par défaut ```tsx render () { return ( <div> <Count /> <button onClick={this.increment}>Increment</button> <button onClick={this.decrement}>Decrement</button> </div> ) } ``` Vous devriez maintenant avoir un projet configuré pour utiliser TypeScript et React, ainsi que les outils pour créer vos propres composants fonctionnels et de composants à base de classe ! ## Exercice - Nous allons créer un composant de gestion des nos bières préférées. Le composant BeerList aure une propritété appelée "beers" qui est un ensemble de vos bières préférées, par exemple "Coreff", "Corona" ou "Mort Subite". Dans le rendering de ce composant, chaque élément contenu dans notre propriété doit instantier un composant appelé Beer en passant une proprité pour le nom de la bière, Cette bière permettra d'afficher le nom dans une balise li dans ce sous-composant. Chaque Bière aura besoin d'une propriété avec un identifiant unique. Vous pouvez utilisez l'index du tableau pour l'instant. - Ajouter la capacité à ajouter ou retirer une bière à notre liste. - Ajouter un composant *about* qui s'affichera quand vous naviguerez jusqu'à l'url /about en utilisant le router de react. Ce composant donnera juste des information sur les auteurs du TP. [documentation](https://reactrouter.com/en/main/start/tutorial) - Passage d'information entre composants en React Je vous rappelle les deux éléments pour permettre la communication entre composants react. https://www.pluralsight.com/guides/react-communicating-between-components et https://www.javascriptstuff.com/component-communication/ Les deux points non abordés ou survolés dans ce petit TP React et portant très important sont: - la gestion de l'état interne du composant et l'utilisation de solution comme Redux pour piloter l'état global de l'application - l'utilisation des hooks permettant entres autres de simplifier en partie les problématiques de gestion d'états à vos heures perdues aller fare ces deux tutos pour comprendre ces concepts. Ces deux tutos devraient vous parler car ils sont batis pour une application de liste de todo ou pour travailler avec des pokemons ;). https://react-redux.js.org/introduction/basic-tutorial https://www.freecodecamp.org/news/building-a-simple-pokemon-web-app-with-react-hooks-and-context-api/ ## Références