The SPA living form
CC-BY-NC-4.0 / Jan. 2021 / Loïc TRUCHOT
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
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> </>
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
Le site de React est bien sûr fait... en React !
Découvrons le découpage par component d'un autre site
mais aussi Airbnb, Netflix, Dropbox, Facebook...
Installer React Developer Tools
-->Explorations d'un projet existant...
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',
},
};
@import "tailwindcss/dist/tailwind.css";
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 ?
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;
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>
Comment agir recharger la vue lorsqu'une valeur change ?
Par exemple, changer la couleur du background si l'utilisateur appuie sur un bouton ?
import React, { useState } from 'react';
const Btn = () => {
const [color, setColor] = useState("blue");
return (<button
style={{"background-color": color}}
onClick={() => setColor("red")}>To red !
</button>);
}
horoscope
chinois 3/5
Méga Bonus:
Remis au goût du jour
NB: les hooks en blancs seront présentées dans un second temps (ou jamais)
function Happy() {
const [happy, setHappy] = useState(true);
return (
<span onClick={() => setHappy(!happy)}>
{happy ? ":)" : ":("}
</span>
);
}
petit rappel
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
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>
);
};
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 />
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `clicked ${count} times`;
}, [count]);
}
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 ?
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'
]
Bonus: chaque son est aussi associé à une touche du clavier
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"
}
import PropTypes from 'prop-types';
https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes
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
Bonus: c'est beau, et ça nous prévient en cas d'erreur
La calculatrice (enfin !)
Ni React / Ni SPA
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>
Toutes les routes mènent à... 1/2
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>
Toutes les routes mènent à... 2/2
Alors qu'on peut s'en passer ?
Rappel
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';
}
}
class Humain extends React.Component {
constructor(props) {
super(props);
this.state = { ami: true };
this.seFacher = this.seFacher.bind(this);
}
seFacher () {
/* ... */
}
}
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...
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
Bonus 1: Vos infos de météo proviennent d'un fichier JSON dans "public"
©1986
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
Bonus: votre component est est horrible, et ses event user loufouques
« J'ai créé un monstre »
Bonus: aidez moi à coder !
Graphiques dynamiques 1/2
ça mansplain grave !
Ces data doivent être:
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 ?
// index.js
import { Provider } from 'react-redux'
import store from './store/store'
<Provider store={store}>
<App />
</Provider>
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>
);
}
Redux
Bonus: Ajouter action "DEFAULT_LANG" au reducer, qui met le site en anglais
const langs = {
fr: {hello: "coucou"},
en: {hello: "hello"}
}
<div>{langs[lang].hello}</div>
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]
}]
Bonus: Une des bulle contient une photo, une autre une vidéo
Mon ami chatbot
↓ Alternative ↓
Bonus: Votre robot peut devener à quoi on pense en nous posant des questions, grâce à une ontologie interne
Bonus: ça doit être beau, avec musique de fond, images et transition smooth
Une ballade en React
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
Custom hooks
THANK'S EVERYONE
It's finally done ! See you soon