React 2021

The SPA living form

CC-BY-NC-4.0 / Jan. 2021 / Loïc TRUCHOT

L'approche React

functional components

  • Une librairie orientée « component »
    • Component = HTML + CSS + JS d'un élément complet (ex: bouton)
    • Un component peut-être instancié x fois, avec des propriété différentes
    • Un component peut en contenir d'autres, la page elle-même est une composition de components
    • Component = simple fonction (ou classe avant la v16)
      • pure fonction qui prends des props et retourne du HTML (jsx)

L'approche React

One way binding && Virtual Dom

  • Data flow simplifié
    • Un component a deux types de data
      • un state (décrit dans le component)
      • des props (attributs données lors de l'instanciation, par le parent)
    • One way binding -> data partagées par les components parents avec leurs enfants
    • Les évènement utilisateurs déclenchent des callbacks partagée avec le parent
  • Virtual DOM
    • JSX pour représenter le HTML dans le JavaScript
    • Un virtual DOM à comparer au DOM
    • Re-render automatique lorsque le state ou les props changent

Où Vit React ?

Workshop

  • D'un seul coup
    • npx create-react-app my-app
  • sinon... installer create-react-app
    • npm i -g create-react-app
  • ...et créer un projet React
    • npm init react-app my-app
  • Installer les dépendances de lancer le projet
  • Afficher "Et c'est reparti !" dans la fenêtre, sur le navigateur
  • afficher un bouton, avec une classe "btn" qui le rend tout rouge

Bonus 2: Ajouter ramda au projet, via NPM, utiliser la fonction ramda replace sur la string "I <3 Angular" pour qu'elle devienne "I <3 React" et afficher cela dans la page

Bonus 1: qd on click dessus, une alert "hello react world" apparaît

CLI

Découvrir JSX

  • public/index.html est vide, sauf 1 div avec l'id root
  • src/index.js lie l'app React et cette div
  • Tout le HTML est généré par le JavaScript de React, mais comment ?
  • Les components React sont (idéalement) des pures fonctions qui
    • prennent un objet "props" en argument
    • retournent un objet JSX que React converti en HTML
  • JSX !== HTML (proche de XHTML)
  • JSX !== React
  • JSX === extension syntaxique de JavaScript
    •  mot-clefs interdits (ex: class -> className, for -> htmlFor)
  • JSX est l'endroit ou l'on compose la vue, en assemblants des components
  • JSX est opposé à l'approche MVC

Les règles de  JSX

  • 1 component retourne 1 element racine JSX
    • eventuellemnt vide
  • balises HTML en minuscules
  • components avec une majuscule
  • attributs sont en camelcase, mais déclarés comme en HTML. Seules les  strings sont entre " ... "
  • Les autres valeurs sont entre { }
  • En fait, {} permet d'interpoler le HTML et le JavaScript
let Cp = () => <div>toto</div>
<h1>toto</h1>
<Cp attr="toto"></Cp>
const Ipt = () => <input value="toto" />
const Ipt = () => <input maxLength={10} />
const List = (props) => <ul>
    { props.items.map(item => <li>{item}</li>) }
  </ul>;
<List items={["a", "b", "c"]} />
let Cp2 = () => <> <p>toto</p> <p>titi</p> </>

Workshop

  • Vider les éléments du component App
  • Créer un nouveau component FormControl, dans FormControl.js
  • C'est une fonction qui reçoit des props et retourne une div, contenant un label et un input
  • Le texte du label est donné via les props
  • <FormControl> est instancié 3x avec les textes "si j'étais un animal:",
    "si j'étais un livre:",
    "si j'étais une vertue:"

Bonus 2: Faire un component de bouton submit, de type "primary"

Questionnaire de Proust

Bonus 1: ajouter bootstrap au projet, donner à la div la class "form-group", donner à l'input la class "form-control"

Bonus 3: Faire un component FormProust contenant les 3 input et le btn

Analyse d'un SPA

En react

Le site de React est bien sûr fait... en React !

Découvrons le découpage par component d'un autre  site

https://asana.com/fr

mais aussi Airbnb, Netflix, Dropbox, Facebook...

Installer React Developer Tools

Structurer un projet react

  • Malheureusement pas de règle !
  • 1 component = 1 fichier
  • dumb et smart components (voir plus loin)
  • architecture fractale ? Une arborescence de components...
  • Atomic design (voir plus loin)
  • Sass ? Eslint ? TypeScript ? Storybook ?
  • propTypes et defaultProps ? (voir plus loin)

-->Explorations d'un projet existant...

Workshop

  • Ajoutons EsLint
    • npm i --save-dev eslint
    • npx eslint --init
    • npm i eslint-plugin-only-warn
  • Ajoutons Sass
    • npm i --save-dev sass
    • conversion css -> scss

bonnes habitudes...

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'plugin:react/recommended',
    'airbnb',
  ],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  plugins: [
    'react',
    'only-warn',
  ],
  rules: {
    'react/react-in-jsx-scope': 'off',
    'react/jsx-filename-extension': 'off',
    'react/prop-types': 'off',
    'linebreak-style': 'off',
    'react/jsx-one-expression-per-line': 'off',
    'no-plusplus': 'off',
    'no-restricted-syntax': 'off',
  },
};

Workshop

  • Trouver les 12 signes chinois et une image pour chaque
  • Faire une "card" tailwind pour chaque signe, en utilisant un component unique
    • npm install tailwindcss --save
    • @import "tailwindcss/dist/tailwind.css";

  • Faire un FormControl demandant l'année de naissance, avec un bouton "valider"
  • onClick sur "valider", une "alerte" nous donne notre signe en fonction de l'année saisie

Bonus: idem pour les 5 éléments de l'Astrologie Chinoise

horoscope chinois 1/5

Bonus 2: Saurez-vous utiliser useRef pour retrouver votre input ?

JSX AVANCÉ

  • whitespaces
    • aucun entre les sauts de ligne
    • 1 max inline
  • boolean attributes
    • pas besoin du ={true}
  • spread attributes
    • comme spread en JS, mais vers du HTML
  • children
    • nom réservé: ce qu'il y a entre les balises (noeuds)
  • key
    • nom réservé: pour optimiser les performances, les éléments produits par une itération veulent une ID
import React from 'react';
import Person from './Person';

const persons = [
  { nom: 'Catwoman', age: 41, inss: 123 },
  { nom: 'Batman', age: 38, inss: 456 },
];
const Family = ({
  children, clazz,
}) => (
  <div className={clazz}>
    {persons.map(
      (p) => (
        <Person
          key={p.inss}
          {...p}
        />
      ),
    )}
    {' '}
    {children}
  </div>
);

export default Family;
const Person = ({ nom, age }) => <div>{nom} {age}</div>;
export default Person;

Workshop

  • Créer un composant de modal
  • Il doit pouvoir s'instancier parfaitement en faisant

Bonus: votre modale est instanciée 3x: main, confirm, error avec une classe et un contenu différent à chaque fois

horoscope chinois 2/5

// dans le corps la fonction App
const attrs = { modalClass: "main-modal", visible: true };

// dans le return de la fonction App
<Modal title="un titre" close {...attrs}>
  Texte de la <strong>modale</strong>.
  {" "}
  Suite du texte.
</Modal>

Les états (ou States)

Et le re-rendering

Comment agir recharger la vue lorsqu'une valeur change ?

Par exemple, changer la couleur du background si l'utilisateur appuie sur un bouton ?

  • La vue se recharge toute seule si
    • une prop change
    • le state change
  • Les props sont données par le composant parent
  • Le state est lié au composant, déclaré grâce au hook useState
import React, { useState } from 'react';

const Btn = () => {
  const [color, setColor] = useState("blue");
  return (<button 
      style={{"background-color": color}} 
      onClick={() => setColor("red")}>To red !
    </button>);
}

Workshop

  • onClick sur "valider"
    • notre signe apparaît à côté du champ
    • Bonus: notre card est "highlightée", mise en valeur
  • Maintenant, en cliquant, cela ouvre la modale, avec tout le contenu a propos de notre signe
    • Utiliser un state booléen dans "app", nommé "visible", que vous passez à la modale
  • Ajouter un bouton "en savoir plus" à tous les signes
  • Cliquer sur le bouton ouvre la modale
    • cliquer sur la croix de la modale la ferme
  • Mettre ce projet sur votre github

horoscope

chinois 3/5

Méga Bonus:

  • La description des signes sur l'accueil ne dépassent plus 150 caractères (troncature)
  • La modale présente le text complet de la description
  • Bonus du bonus: la troncatures ne s'arrête pas exactement à 150, mais au dernier mot complet avant 150...

React Hooks

In deep

UN vieux concept

Remis au goût du jour

  • React = fonctionnel 
  • Comment gérer le cycle de vie / les options de rendering, sans méthode liée à une classe ?
  • Une classe règle bien des problèmes:
    • La classe React contient toutes les méthodes utiles
    • La class contient le state qui re-render
    • Le codeur l'étend avec ses cas particuliers et ses data
  • Les Hooks existent depuis toujours en informatique: il s'agit d'une injection de code à un endroit du programme
  • hook into = introduire/intégrer
  • Dans le cas de React, on injecte le code liée au state/re-rendering dans le Functional Component...
  • ...et hop ! Plus besoin de classes !

CB de Hooks ?

  • useState
  • useEffect
  • useContext
  • useReducer
  • useRef
  • ...
  • custom
    • useToto

Qu'apportent-t-ils ?

  • conserver des valeurs entre re-render
  • contrôle les effets de bords
  • utiliser une globale partagée entre plusieurs cpts
  • éviter la dépendance Redux, states immutables
  • référencer un élement du DOM ou valeur mutable
  • plusieurs autres plus confidentielles
  • Mes propres hooks !

NB: les hooks en blancs seront présentées dans un second temps (ou jamais)

useSTATE

function Happy() {
  const [happy, setHappy] = useState(true);
  return (
    <span onClick={() => setHappy(!happy)}>
      {happy ? ":)" : ":("}
    </span>
  );
}
  • Tout logiciel est en fait une machine à états, comme l'est l'odinateur.
  • Idem pour une vidéo
  • Un état doit être mémorisé, alors qu'une fonction react est pure qui s'exécute pour "render"
  • On utilise donc un "hook" pour sortir l'état de la fonction 

petit rappel

Workshop

  • Notre application permet aux journalistes de garder un compte en live des médailles gagnées par les différentes nations
  • Il y a un tableau dans la vue, et 5 useStates() 
    • Belgique | France | Corée | USA | Laos
    • 3                | 2           | 4         | 6       | 12
  • Il y a un bouton-drapeau pour chaque pays
  • Quand on clique dessus, le compte de médaille augmente pour le pays concerné
  • Sous le tableau il y une icône de médaille, et le nom de·s pays actuellement premier·s

Dans tous ces états

Bonus 1: Il n'y a qu'un seul useState pour tout ça, au lieu de 5

Bonus 2: Le compte est plus précis: or, argent bronze, idem pour la mise en avant sous le tableau: total ou par médaille

useREF

const Song = () => {
  const audioEl = useRef(null);
  return (
    <div>
      <button onClick={() => { audioEl.current.play();}} />
      <audio preload="auto" ref={audioEl}>
        <source src="toto.mp3" type="audio/mpeg" />
      </audio>
    </div>
  );
};
  • Un element du HTML  conservé comme un "state"
  • Associé dès le premier render
  • utilisable dans les fonctions et dans les effets
  • S'utilise avec le .current de la Ref
  • S'associe avec l'attribut réservé ref

Workshop

  • Usage getElementById/querySelector interdit
  • Dans un seul <Budget />, nous produisons un simple feuille de calcul
  • L'utilisateur rentre son salaire dans un premier <input />
  • Il clique sur un <button> "valider", le champ devient disabled
  • En dessous, il y a 4 autres <input />
    • loyer, charges, courses, sorties
    • changer le contenu d'un des champs change le total
  • On trouve ce total en bas dans un <p>

Bonus 1: A coté du total, il y a un smiley. Si total positif -> sourire, équilibré -> pokerface, négatif -> pleure

le budget qui pleure

Bonus 2: Les champs et leur noms sont passés en props à <Budget />

useeffect

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `clicked ${count} times`;
  }, [count]);
}
  • Se déclenche à chaque render, dont le premier !
  • Utile pour lancer une action asynchrone, puis utiliser setState (typiquement interroger une base de donnée
  • Si 2ème argument est un tableau vide, ne se déclenche qu'une fois
  • Si 2ème argument est un tableau de states, se déclenchent lorsque ces states changent

Workshop

  • Consommer les data d'horoscope avec fetch et useEffect
  • L'input est désormais un useRef

horoscope chinois 4/5

Bonus 2: Existe-il un algorithme qui marche/s'approche au maximum pour calculer le vrai signe au jour près ?

Bonus 1: Installer la librairie axios et faite la même requête ajax avec axios. En quoi axios est différent ?

Workshop

  • Faire une app musicale sur l'air de Daft Punk - Harder, Better, Faster, Stronger
  • Le son "song-instrumental" se lance lorsqu'on clique sur un triangle "play"

Bonus 3: Faire un bouton déclenchant 3 sons d'affilés

Toujours plus fort (featuring daft punk)

Bonus 2: Faire des boutons stop/start/restart

Bonus 4: Effets disco + mot cliqué qui grossi et fade out

[
  'work it', 'make it', 'do it', 'makes us',
  'harder', 'better', 'faster', 'stronger',
  'more than', 'hour', 'our', 'never',
  'ever', 'after', 'work is', 'over'
]
  • La souris peut déclencher chaque son en cliquant sur des boutons

Bonus: chaque son est aussi associé à une touche du clavier

Prop-types

  • JS typage faible et dynamique 
    • erreurs au runtime
    • manque de documentation
  • En React:
    • typo sur une prop
    • oublie d'une prop requise
    • composant incompréhensible
  • Solution radicale: TypeScript
  • Solution légère : prop-types
    • F.propTypes pour typer
    • F.defaultProps pour donner des valeurs par défaut
  • Tous types
    • primitif
    • object, func, any
    • oneOf, arrayOf, shape
const FormControl = ({phText, labelText}) => (
  <div className="form-group">
    <label>{labelText}: </label>
    <input 
      className="form-control" 
      placeholder={phText} 
    />
  </div>);
  
  FormControl.propTypes = {
    labelText: PropTypes.string.isRequired,
    phText: PropTypes.string
  }
  
  FormControl.defaultProps = {
    phText: "Taper ici"
  }
  • npm install prop-types --save
  • import PropTypes from 'prop-types';

https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes

Workshop

  • PropTypes et defaultProps everywhere

horoscope chinois 5/5

Bonus 1: En fonction d'un <select> Zodiaque/Chinoise, l'horoscope est changé en signes européen ou chinois, de même que toutes les mécaniques

Bonus 2: Un algorithme permet de savoir, selon notre signe de naissance et celui d'un·e autre, si on a une chance de faire un bon couple

Workshop LIBRE

  • Faire un nouveau projet react avec NPX
  • Ajouter eslint, sass (bootstrap en option)
  • Proposer une caculatrice avec les nombres de 0 à 9, les 4 opérations principales
  • un affichage des opérations en cours
  • un affichage du résultat, et un bouton "="
  • propTypes et propDefault everywhere !

Bonus: c'est beau, et ça nous prévient en cas d'erreur

La calculatrice (enfin !)

router

Ni React / Ni SPA

Le routing client c'est

  • L'illusion d'un changement de page
  • La capacité de partager une URL
  • Une source de vérité pour l'état de l'application
  • WARNING: l'ordre du Switch compte !
    • la home "/" est en dernier, car tous matchent "/..."

Contrairement à Vue ou Angular,

React n'a de Router officiel

Il en existe plusieurs, le plus utilisé est : react-router-dom

Les routes sont de simples components... instanciés de façon conditionelle

import {
  Route, BrowserRouter as Router, Switch, Link,
} from 'react-router-dom'; 

<Router>
  <div>
    <Link to="/">Home</Link> 
    <Link to="/about">About</Link> 
    <Link to="/topics">Topics</Link>
    <Switch>
      <Route path="/about">
        <About />
      </Route>
      <Route path="/topics">
        <Topics />
      </Route>
      <Route path="/">
        <Home />
      </Route>
    </Switch>
  </div>
</Router>

Workshop

Toutes les routes mènent à...   1/2

  • Créer une nouvelle app "little-italy"
  • Installer react-router-dom
  • Produire un menu pour atteindre 4 routes/components:
    • /: un accueil, intro, mise en avant d'une ville d'italie
    • /liste: de 3 villes italiennes
    • /fiche: une ville italienne
    • /voyage: formulaire d'inscription pour un voyage touristique

Le routing client c'est AUSSI

  • de très nombreux cas spéciaux
  • une mécanique de navigation interne
  • souvent un système liste/fiche
  • pour gérer cela, react-router-dom offre... des hooks !
  • useParams, useRouteMatch....

React-router-dom suit  des conventions classiques de routing

Il épouse bien REST

 

import { useParams } from "react-router-dom";
const Topic = () => {
  let { slug } = useParams();
  return (<h3>Requested topic: {slug}</h3>);
}

export default Topic;
    <Router>
    <div>
      <Link to="/topic/programming">programming</Link>
      <Link to="/topic/dancing">dancing</Link>
      <Switch>
        <Route path="/topic/:slug">
         <Topic />
        </Route>
      </Switch>
    </div>
  </Router>

Workshop

  • Créer un array pour ces villes, avec:
    • nom, description, slug, image, longitude, latitude
  • La liste est basée sur cette array, cliquer mène aux fiches
  • La fiche est basée sur un élément de l'array
    • la route de la fiche est désormais de  type "/fiche/:slug"
    • où :slug est un param qui sert à savoir quelle ville afficher
  • La ville de la home est prise au hasard dans l'array, cliquer mène à la fiche

Toutes les routes mènent à...   2/2

Class components

Know them, don't use them

Pourquoi des class

Alors qu'on peut s'en passer ?

  • Aux débuts de React, pas de "usestate" (existe depuis 1 an)
  • Presentational component = function
  • Stateful component = class étendant une class Component
  • Propriétés
    • props (objet externe)
    • state (objet interne, déclaré dans constructor)
  • Méthodes utiles pour gérer les états
    • render(), pour le JSX
    • componentDidMount(), creation
    • componentUpdate(), changement d'état
    • componentWillUnmount(), destruction
  • Reason et ReasonReact: un avenir fonctionnel ?

ES6 classes

Rappel

  • constructor
  • this
  • propriétés
  • méthodes
  • extends et super
  • new (return this)
  • Un fichier par classe

 

Pur syntactic sugar pour des fonction constructor renvoyant un nouvel objet avec le même prototype

// classes
export class Game {
  constructor(gameName, nbPlayers) {
    this.nbPlayers = nbPlayers;
    this.gameName = gameName;
    this.editor = 'Pay2Win Corp.';
  }
  // shorthand method
  launch() {
    console.log(`${this.editor} game 
	  named ${this.gameName} will begin !`);
  }
}

export class Quizz extends Game {
  constructor(gameName, nbPlayers) {
    super(gameName, nbPlayers);
    this.type = 'Quizz';
  }
}

Le constructeur

D'un component react

class Humain extends React.Component {
  constructor(props) {
    super(props);
    this.state = { ami: true };
    this.seFacher = this.seFacher.bind(this);
  }
  seFacher () {
    /* ... */
  }
}
  • on étend React.Component
  • super est obligatoire pour rendre les props réactives
  • le state réactif est déclaré dans le constructor
  • this doit être rebindé pour toutes les méthodes custom
  • on peut utiliser les méthodes de React.Component comme setState

Methodes de react en action

 

 

 

 

 

class Humain extends React.Component {
  constructor(props) {
    super(props);
    this.state = { ami: true };
    this.seFacher = this.seFacher.bind(this);
  }
  seFacher () {
    this.setState({ ami: false });
  }
  render () {
    return (
      <button onClick={this.seFacher}>
      	{this.props.content}
      <button>
    );
  }
}

Mais aussi: componentDidMount, componentDidUpdate...

Workshop

Bonus 2: Trouver un vraie API de météo sur le web (openweathermap ?), ainsi qu'un date picker, pour faire la même chose

La pluie et le beau temps

  • On créer un app mobile-first pour faire voir la météo
  • Dans le constructor, créer un tableau comprenant la météo pour les 7 jours de la semaine
  • Montrer automatiquement la météo d'aujourd'hui
  • Grâce à 7 boutons des jours de la semaine, on peut voir la météo des autres jours (utiliser "setState")

Bonus 1: Vos infos de météo proviennent d'un fichier JSON dans "public"

The mess we made

featuring storybook

les webapps sont comme...

  • Des villes, avec un petit coeur
  • Il faut très vite tout changer, pour "scaler"
  • Qd tout se mélange, rien n'est réutilisable
  • En plus, la communication avec les différentes parties prenante n'est pas facile, et tout change en cours de route

©1986

We need a hero

storybook !

un outil visuel

  • Pour isoler
  • Pour démontrer
  • Pour raisonner ensemble
  • Pour réutiliser et faire évoluer

 

Projet open source disponible sur NPM... mais ce qui compte c'est le concept, le manière d'approcher le développement web en général

Workshop

  1. Creation d'un repo github collectif
  2. Installation de story book et push
    • ​​npm install -g @storybook/cli
    • sb init --type react_scripts
  3. Pull collectif
  4. Creation massive de components anarchiques
  5. Instanciation de ces components dans storybook
  6. Utiliser les components fait par les autres pour composer une app la plus moche possible !

Bonus: votre component est est horrible, et ses event user loufouques

« J'ai créé un monstre »

Observation d'une APP reele

Bonus: aidez moi à coder !

Smart et Dumb components

Contenu vs presentation

  • Dans un app, la complexité vient souvent du nombre de states possibles, et de la dispersion des data
  • Que faire si deux components ont besoins de la même data ? Et peuvent la modifier ?
  • Une architecture très utilisée en SPA
    • Faire un component "container" (smart) contenant les datas et le state
    • Faire plein de component "presentational" (dumb / stateless) ne recevant que des props, et des callbacks pour les modifier
  • Cette architecture est proche de Redux (voir plus loin)

Workshop

  • Créer une nouvelle app react
  • Installer une dépendance pour les graphiques
    • npm install chart.js --save
  • Les data d'un graphique "chart.js" sont souvent un tableau de number
    • Donnez vous une note de 0 à 100 en HTML, CSS, JS, PHP, Python
      • ex: [12, 34, 99, 13, 0]

Graphiques dynamiques 1/2

ça mansplain grave !

Ces data doivent être:

  • un state
  • Affichée dans le JSX
  • A côté de 5 inputs de type "range" qui peuvent en faire varier la valeur
  • setState devrait prendre un nouveau tableau tout neuf à chaque fois, avec la bonne valeur modifiée

Workshop

  • Votre app contient 3 routes (hookrouter) :
    • / et /bar
    • Lorsqu'on arrive sur /bar, un graphique en barre est montré

Graphiques dynamiques 2/2

OMG j'aurais du vendre mes bitcoins

import { Chart } from "chart.js";
const ctx = chartElRef.current.getContext('2d');
new Chart(ctx, {
  type: 'bar',
  data: {
    labels: ['HTML', 'CSS', 'JavaScript', 'PHP', 'Python'],
    datasets: [{
      label: 'Mes compétences',
      data: "????",
      backgroundColor: ['red', 'green', 'blue', 'violet', 'pink'],
    }]
  }
});
<canvas width="200" height="200" />

D'où vient

chartElRef ?

Que faire avec ?

Que faut-il mettre dans les data ?

  • Dans quel hook faut-il déclarer le new Chart() ?
  • Mettre le new Chart() dans une ref useRef nommé barGraph
  • L'effet de bord barGraph.update() met à jour le graphique. Quand doit-il avoir lieu ? Bonus: ajouter un graphique en "line" ou d'autres encore.

Une nouvelle problématique

  • Que faire des data répétées entre components et des states globaux ?
  • Que faire des states partagés entre component sans racines communes ?
  • Où seront nos data si on doit changer de framework ?
  • Rappelez-vous: logiciel = data + function: l'un où l'autre devrait pouvoir changer indépendamment
  • La solution classique: le store. Mais attention...
    • pas de store natif en React
    • boilerplate : des nouveaux fichier en masse
    • complexité : selecors, reducers, actions, dispatch
    • fonctions pure et immutabilité

Le Store le plus classique: Redux

  • Mais quelques concurrents: MobX, nouvelles hooks useReducers...
  • Installation: npm install --save redux react-redux
// index.js
import { Provider } from 'react-redux'
import store from './store/store'
<Provider store={store}>
  <App />
</Provider>
  • N'importe quel noeud de l'application peut désormais accéder au store
const init = { mood: ":)" };
const moodReducer = (state = init, action) => {
    switch (action.type) {
        case "CHANGE_MOOD": 
            return {...state, mood: action.mood };
        default: 
            return state;
    }
}
export default moodReducer;
import { createStore } from 'redux';
import moodReducer from './mood/reducer';
export default createStore(moodReducer);
import { useSelector, useDispatch } from 'react-redux';
const App = () => {
  const dispatch = useDispatch();
  const mood = useSelector((state) => state.mood);
  return (   
    <button onClick={() => dispatch({
        type: "CHANGE_MOOD", 
        mood: mood === ":)" 
    		? ":(" 
    		: ":)"})
      }>Toggle mood {mood}</button>
  );
}
  • App.js accede au store,
  • les hooks redux remplacent useState/setState
  • mood reducer.js est une partie du store

Workshop

  • Les langues sont typiquement des data présentent en parallèle dans l'app
  • Implémenter un store avec un reducer capable de changer la langue de l'App
    • installer redux et react-redux
    • créer un reducer pour la langue
    • créer un store basé sur ce reducer

Redux

  • Importer useDispatch et useSelector dans App.js
  • Créer 2 components imbriqué dans le JSX d'App
  • Créer un objet langs sur ce modèle

Bonus: Ajouter action "DEFAULT_LANG" au reducer, qui met le site en anglais

const langs = {
  fr: {hello: "coucou"},
  en: {hello: "hello"}
}
  • utiliser ces langues dans les components de cette façon
<div>{langs[lang].hello}</div>
  • enfin, faire un <select> permettant de changer de langue dans toute l'app

React et Typescript

Match ?

Workshop

  • On travaille sur une app de basket-ball
  • Creer un nouveau projet react avec typescript
    • npx create-react-app bb --template typescript
  • Ajouter eslint
    • npx eslint --init
      • bien choisir typescript
  • Créer un fichier TS typé avec différentes infos de match

typescript

[{
  id: "XM284",
  name: "Amicale nat. fém. Junior Rennes-Vannes Jan. 2017",
  teams: [
    {
      city: "rennes", level: "j", color: "red", id: 35,
      cap: { nom: "Salima Belhadj", img: "salima.jpg" }
    }, 
    {
      city: "vannes", level: "j", color: "black", id: 56,
      cap: { nom: "Aurélie Menard", img: "aurelie.jpg"}
    }
  ],
  winner: 35,
  scores: [74, 49],
  fautes: [3, 9]
}]
  • Créer un component de présentation de match
  • Itérer sur vos match pour les présenter
  • Les deux couleurs des deux teams apparaissent
  • TOUT EST TYPÉ !

Workshop

  • Creer un component Chat, qui a une liste de components "Bubble"
  • Les Bubbles sont différents message que l'user et le bot s'écrivent

Bonus: Une des bulle contient une photo, une autre une vidéo

Mon ami chatbot

  • Le bot pose des questions auxquelles l'user peut répondre via un choix multiple
  • Selon sa réponse, une bulle en rapport avec la réponse est affichée

↓ Alternative ↓

Bonus: Votre robot peut devener à quoi on pense en nous posant des questions, grâce à une ontologie interne

Workshop

  • Le component App sera le seul contenant des « états »
  • Creer un component Walk, qui contient 4 components Direction pour le 4 point cardinaux
  • Creer un component Story, qui contient le texte visible actuellement

Bonus: ça doit être beau, avec musique de fond, images et transition smooth

Une ballade en React

  • On part du texte central
  • Lorsqu'on clic pour aller dans une direction, le texte change en fonction de la "place" dans le tableau ci-contre
  • Les points cardinaux apparaissent et disparaissent selon l'existence du lieu
const places = [
  ["ne", "nc", "nw"],
  ["e", "c", "w"],
  ["se", "sc", "sw"],
];

Bonus: Agrandissez ce tableau de direction

Bonus: Prévoir une représentation graphique sous forme de map cliquable

Autres Hooks

Custom hooks

WS chat collectif

THANK'S EVERYONE
It's finally done ! See you soon

React 2021 - The SPA living form

By Loïc TRUCHOT

React 2021 - The SPA living form

Introduction à React, en français et sans compromis.

  • 1,115