Dans cette partie de la traduction du cours de formation React, vous êtes invité à créer un générateur de mèmes.

→
Partie 1: aperçu du cours, raisons de la popularité de React, ReactDOM et JSX→
Partie 2: composants fonctionnels→
Partie 3: fichiers composants, structure du projet→
Partie 4: composants parent et enfant→
Partie 5: début des travaux sur une application TODO, les bases du style→
Partie 6: sur certaines fonctionnalités du cours, JSX et JavaScript→
Partie 7: styles en ligne→
Partie 8: poursuite des travaux sur l'application TODO, familiarité avec les propriétés des composants→
Partie 9: propriétés des composants→
Partie 10: Atelier sur l'utilisation des propriétés et du style des composants→
Partie 11: génération de balisage dynamique et méthode des tableaux de cartes→
Partie 12: atelier, troisième étape de travail sur une application TODO→
Partie 13: composants basés sur les classes→
Partie 14: atelier sur les composants basés sur les classes, état des composants→
Partie 15: ateliers santé composante→
Partie 16: quatrième étape de travail sur une application TODO, gestion d'événements→
Partie 17: cinquième étape de travail sur une application TODO, modifiant l'état des composants→
Partie 18: la sixième étape de travail sur une application TODO→
Partie 19: méthodes du cycle de vie des composantsPartie 20: la première leçon de rendu conditionnel→
Partie 21: deuxième leçon et atelier sur le rendu conditionnel→
Partie 22: la septième étape des travaux sur une application TODO, téléchargement de données depuis des sources externes→
Partie 23: première leçon sur l'utilisation des formulaires→
Partie 24: Deuxième leçon sur les formulaires→
Partie 25: Atelier sur l'utilisation des formulaires→
Partie 26: architecture d'application, modèle de conteneur / composant→
Partie 27: projet de coursLeçon 45. Projet de cours. Générateur de mème
→
OriginalNous sommes donc arrivés au projet de cours. Créons une application qui va générer des mèmes. Commençons par le projet standard create-react-app créé à l'aide de cette commande:
npx create-react-app meme-generator
Ici vous pouvez trouver des informations sur les caractéristiques de son utilisation.
Au cours des travaux sur ce projet, il vous sera demandé d'implémenter vous-même certaines de ses parties, puis de lire les explications les concernant. Le projet standard a déjà du code
index.js
-
App.js
situé, en particulier, dans les
App.js
index.js
et
App.js
Vous pouvez supprimer complètement ce code et essayer de l'écrire vous-même afin de vous tester dans l'implémentation des mécanismes standards des applications React.
Dans ce projet, vous êtes invité à utiliser les styles suivants:
* { box-sizing: border-box; } body { margin: 0; background-color: whitesmoke; } header { height: 100px; display: flex; align-items: center; background: #6441A5; background: -webkit-linear-gradient(to right, #2a0845, #6441A5); background: linear-gradient(to right, #2a0845, #6441A5); } header > img { height: 80%; margin-left: 10%; } header > p { font-family: VT323, monospace; color: whitesmoke; font-size: 50px; margin-left: 60px; } .meme { position: relative; width: 90%; margin: auto; } .meme > img { width: 100%; } .meme > h2 { position: absolute; width: 80%; text-align: center; left: 50%; transform: translateX(-50%); margin: 15px 0; padding: 0 5px; font-family: impact, sans-serif; font-size: 2em; text-transform: uppercase; color: white; letter-spacing: 1px; text-shadow: 2px 2px 0 #000, -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 0 2px 0 #000, 2px 0 0 #000, 0 -2px 0 #000, -2px 0 0 #000, 2px 2px 5px #000; } .meme > .bottom { bottom: 0; } .meme > .top { top: 0; } .meme-form { width: 90%; margin: 20px auto; display: flex; justify-content: space-between; } .meme-form > input { width: 45%; height: 40px; } .meme-form > button { border: none; font-family: VT323, monospace; font-size: 25px; letter-spacing: 1.5px; color: white; background: #6441A5; } .meme-form > input::-webkit-input-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input::-moz-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-ms-input-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-moz-placeholder { font-family: VT323, monospace; font-size: 25px; text-align: cen }
Ces styles peuvent être inclus dans le fichier
index.css
déjà dans le projet et
index.css
dans le fichier
index.js
.
Ainsi, en supposant que les fichiers
index.js
et
App.js
sont maintenant vides, vous, en tant que première tâche, êtes invité à écrire le code
index.js
-
index.js
, à créer le composant le plus simple dans
App.js
et à le
index.js
dans
index.js
.
Voici ce qui devrait apparaître dans
index.js
:
import React from "react" import ReactDOM from "react-dom" import './index.css' import App from "./App" ReactDOM.render(<App />, document.getElementById("root"))
Ici, nous importons
React
et
ReactDOM
, importons des styles depuis
index.css
et le composant
App
. Après cela, en utilisant la méthode
ReactDOM.render()
, nous
ReactDOM.render()
ce que le composant
App
forme dans l'élément de la page
index.html
avec l'identifiant
root
(
<div id="root"></div>
).
Voici à quoi pourrait ressembler le fichier
App.js
:
import React from "react" function App() { return ( <h1>Hello world!</h1> ) } export default App
Voici maintenant présenté le composant fonctionnel le plus simple.
À ce stade, le projet ressemble à celui illustré ci-dessous.
Application dans le navigateurCréez maintenant deux nouveaux composants, dans deux fichiers dont les noms correspondent aux noms des composants:
- Composant d'en-
Header
qui sera utilisé pour afficher l'en-tête de l'application. - Le composant
MemeGenerator
, dans lequel les principales tâches assignées à l'application seront résolues. À savoir, les appels à l'API seront effectués ici. Les données d'application seront stockées ici.
En considérant les fonctions attribuées à ces composants, pensez à ce qu'elles devraient être.
Voici le contenu du fichier
Header.js
:
import React from "react" function Header() { return ( <h1>HEADER</h1> ) } export default Header
Étant donné que ce composant ne sera utilisé que pour afficher l'en-tête de l'application, nous l'avons conçu comme un composant fonctionnel.
Voici le code du fichier
MemeGenerator.js
:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state ={} } render() { return ( <h1>MEME GENERATOR SECTION</h1> ) } } export default MemeGenerator
Ici, en tenant compte des tâches qui sont supposées être résolues au moyen du composant
MemeGenerator
, nous utiliserons un composant basé sur la classe. Il y a un constructeur ici dans lequel nous initialisons l'état avec un objet vide.
Après avoir créé ces fichiers, nous les importons dans
App.js
et
App.js
le balisage du composant fonctionnel de l'
App
, qui utilise des instances de ces composants, sans oublier que si le composant fonctionnel renvoie plusieurs éléments, ils doivent être enveloppés dans quelque chose. Dans notre cas, il s'agit de la
<div>
. Voici le code
App.js
mis à jour:
import React from "react" import Header from "./Header" import MemeGenerator from "./MemeGenerator" function App() { return ( <div> <Header /> <MemeGenerator /> </div> ) } export default App
Vérifiez l'apparence de l'application.
Application dans le navigateurMaintenant, travaillons sur le composant
Header
. Ici, nous allons utiliser l'élément sémantique HTML5
<header>
. Cette balise contiendra l'image et le texte. Maintenant, le code du fichier
Header.js
ressemblera à ceci:
import React from "react" function Header() { return ( <header> <img src="http://www.pngall.com/wp-content/uploads/2016/05/Trollface.png" alt="Problem?" /> <p>Meme Generator</p> </header> ) } export default Header
Voici comment l'apparence de l'application va changer.
Application dans le navigateurLe titre de l'application est conçu conformément aux styles précédemment
index.js
dans
index.js
. Le travail sur le composant
Header
-
Header
est maintenant terminé.
Nous continuerons de traiter le composant
MemeGenerator
. Vous êtes maintenant invité à initialiser indépendamment l'état de ce composant en lui écrivant les données suivantes:
- Le texte affiché en haut du mème (propriété
topText
). - Le texte affiché en bas du mème (propriété
bottomText
). - Image aléatoire (propriété
randomImage
qui doit être initialisée avec le lien http://i.imgflip.com/1bij.jpg ).
Voici ce que
MemeGenerator.js
code
MemeGenerator.js
après avoir initialisé l'état:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg" } } render() { return ( <h1>MEME GENERATOR SECTION</h1> ) } } export default MemeGenerator
Maintenant, l'apparence de l'application ne sera pas affectée.
Nous utiliserons des appels à l'API, qui renvoie un tableau d'objets contenant des liens vers des images, en fonction des mèmes qui peuvent être créés. À ce stade du travail sur le projet, vous êtes invité à implémenter les fonctionnalités suivantes dans le composant
MemeGenerator
:
- Appelez l'API https://api.imgflip.com/get_memes/ .
- Enregistrez les données disponibles dans la réponse en tant que tableau de
response.data.memes
dans la nouvelle propriété d'état ( allMemeImgs
).
Ici, pour être plus clair, un fragment des données JSON retourné lors de l'accès à cette API:
{ "success":true, "data":{ "memes":[ { "id":"112126428", "name":"Distracted Boyfriend", "url":"https:\/\/i.imgflip.com\/1ur9b0.jpg", "width":1200, "height":800, "box_count":3 }, { "id":"87743020", "name":"Two Buttons", "url":"https:\/\/i.imgflip.com\/1g8my4.jpg", "width":600, "height":908, "box_count":2 }, { "id":"129242436", "name":"Change My Mind", "url":"https:\/\/i.imgflip.com\/24y43o.jpg", "width":482, "height":361, "box_count":2 }, …. ] } }
Pour résoudre le problème posé ci-dessus, il est nécessaire de prendre en compte le fait que nous parlons de données dont le composant a besoin au tout début de l'application.
Par conséquent, pour les charger, nous allons recourir à la méthode du cycle de vie du
componentDidMount()
. Ici, nous, en utilisant la méthode standard
fetch()
, nous appellerons l'API. Cela renvoie une promesse. Après avoir chargé les données, l'objet de réponse sera disponible pour nous, à partir de là, nous extrayons le tableau
memes
et le mettons dans la nouvelle propriété d'état
allMemeImgs
, initialisée avec un tableau vide. Étant donné que ces données ne sont pas encore utilisées pour former quelque chose qui s'affiche à l'écran, nous imprimerons le premier élément du tableau sur la console pour vérifier le bon fonctionnement du mécanisme de chargement des données.
Voici le code du composant
MemeGenerator
à ce stade de travail:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data console.log(memes[0]) this.setState({ allMemeImgs: memes }) }) } render() { return ( <h1>MEME GENERATOR SECTION</h1> ) } } export default MemeGenerator
C'est ce qui arrive à la console après avoir réussi à charger les données.
Application dans le navigateur, sortie sur la console du premier élément du tableau chargéNotez que l'image est décrite à l'aide de nombreuses propriétés. Nous n'utiliserons que la propriété
url
, qui donne accès au lien pour télécharger l'image.
Au début du cours, nous avons parlé de l'apparence de cette application.
Générateur de mèmeEn particulier, son interface possède quelques champs de saisie de texte, qui seront affichés dans les parties supérieure et inférieure de l'image. Vous êtes maintenant invité à prendre, sur la base du code mis à jour du composant
MemeGenerator
illustré ci-dessous, qui diffère du code ci-dessus de ce composant en ce qu'un
topText
formulaire est ajouté ici, pour créer vous-même quelques champs de texte,
topText
et
bottomText
. N'oubliez pas que ces composants doivent être gérés. Ajoutez-leur les attributs nécessaires. Créez un
onChange
événements
onChange
ces champs dans lequel vous devez mettre à jour les propriétés d'état correspondantes lorsque vous y entrez du texte.
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } render() { return ( <div> <form className="meme-form"> { // } <button>Gen</button> </form> </div> ) } } export default MemeGenerator
Soit dit en passant, faites attention au fait que pour inclure un commentaire dans le code retourné par la méthode
render()
, nous l'avons placé entre crochets afin d'indiquer au système que ce fragment doit être interprété comme du code JavaScript.
Voici ce que vous devriez obtenir à ce stade du travail sur l'application:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } render() { return ( <div> <form className="meme-form"> <input type="text" name="topText" placeholder="Top Text" value={this.state.topText} onChange={this.handleChange} /> <input type="text" name="bottomText" placeholder="Bottom Text" value={this.state.bottomText} onChange={this.handleChange} /> <button>Gen</button> </form> </div> ) } } export default MemeGenerator
Maintenant, la page d'application ressemblera à celle illustrée ci-dessous.
Application dans le navigateurBien que seuls les champs contenant du texte d'aide soient affichés, la saisie de données dans ceux-ci n'entraîne pas de modifications dans l'interface. Afin de vérifier le bon fonctionnement des mécanismes implémentés ici, vous pouvez utiliser la commande
console.log()
.
Nous allons maintenant travailler sur la partie de l'application qui est responsable de l'affichage de l'image-meme. Rappelons que nous avons maintenant un tableau contenant des informations sur les images qui sont prévues pour être utilisées comme base de mèmes. L'application devrait, en appuyant sur le bouton
Gen
, sélectionner au hasard une image de ce tableau et former un meme.
Voici le code mis à jour pour le composant
MemeGenerator
. Ici, dans la méthode
render()
, sous le code de description de formulaire, il y a un élément
<div>
, qui comprend un élément
<img>
qui affiche une image, et quelques éléments
<h2>
qui affichent des étiquettes. Les éléments
<div>
et
<h2>
sont conçus en utilisant des styles que nous avons ajoutés au projet au tout début du travail sur celui-ci.
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } render() { return ( <div> <form className="meme-form"> <input type="text" name="topText" placeholder="Top Text" value={this.state.topText} onChange={this.handleChange} /> <input type="text" name="bottomText" placeholder="Bottom Text" value={this.state.bottomText} onChange={this.handleChange} /> <button>Gen</button> </form> <div className="meme"> <img align="center" src={this.state.randomImg} alt="" /> <h2 className="top">{this.state.topText}</h2> <h2 className="bottom">{this.state.bottomText}</h2> </div> </div> ) } } export default MemeGenerator
Voici à quoi ressemble l'application maintenant.
Application dans le navigateurFaites attention au fait que l'image qui a initialisé l'état est affichée ici. Nous n'utilisons pas encore d'images stockées dans la propriété d'état
allMemeImgs
. Essayons d'entrer quelque chose dans les champs de texte.
Application dans le navigateurComme vous pouvez le voir, les sous-systèmes d'application chargés de travailler avec du texte fonctionnent comme prévu. Maintenant, il ne reste plus qu'à s'assurer qu'en cliquant sur le bouton
Gen
une image aléatoire est sélectionnée dans le tableau avec les données d'image et chargée dans l'élément
<img>
, qui est présent sur la page sous les champs de saisie de texte.
Afin d'équiper l'application de cette fonctionnalité, effectuez la tâche suivante. Créez une méthode qui se déclenche lorsque vous cliquez sur le bouton
Gen
. Cette méthode doit sélectionner l'une des images dont les informations sont stockées dans la propriété d'état
allMemeImgs
, puis effectuer des actions qui vous permettent d'afficher cette image dans l'élément
<img>
situé sous les champs de saisie de texte.
allMemeImgs
à l'
allMemeImgs
que
allMemeImgs
stocke un tableau d'objets qui décrivent des images et que chaque objet de ce tableau a une propriété
url
.
Voici le code qui fournit une solution à ce problème:
import React, {Component} from "react" class MemeGenerator extends Component { constructor() { super() this.state = { topText: "", bottomText: "", randomImg: "http://i.imgflip.com/1bij.jpg", allMemeImgs: [] } this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) } componentDidMount() { fetch("https://api.imgflip.com/get_memes") .then(response => response.json()) .then(response => { const {memes} = response.data this.setState({ allMemeImgs: memes }) }) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } handleSubmit(event) { event.preventDefault() const randNum = Math.floor(Math.random() * this.state.allMemeImgs.length) const randMemeImg = this.state.allMemeImgs[randNum].url this.setState({ randomImg: randMemeImg }) } render() { return ( <div> <form className="meme-form" onSubmit={this.handleSubmit}> <input type="text" name="topText" placeholder="Top Text" value={this.state.topText} onChange={this.handleChange} /> <input type="text" name="bottomText" placeholder="Bottom Text" value={this.state.bottomText} onChange={this.handleChange} /> <button>Gen</button> </form> <div className="meme"> <img align="center" src={this.state.randomImg} alt="" /> <h2 className="top">{this.state.topText}</h2> <h2 className="bottom">{this.state.bottomText}</h2> </div> </div> ) } } export default MemeGenerator
Le bouton
Gen
peut se voir attribuer un gestionnaire d'événements qui se produit lorsque vous cliquez dessus, comme c'est le cas avec tous les autres boutons. Cependant, étant donné que ce bouton est utilisé pour soumettre le formulaire, il serait préférable d'utiliser le
onSubmit
événements
onSubmit
formulaire. Dans ce gestionnaire,
handleSubmit()
, nous appelons la méthode de l'
event.preventDefault()
vient afin d'annuler la procédure de
event.preventDefault()
formulaire standard, pendant laquelle la page est rechargée. Ensuite, nous obtenons un nombre aléatoire dans la plage de 0 à la valeur correspondant à l'index du dernier élément du tableau
allMemeImgs
et utilisons ce nombre pour faire référence à l'élément avec l'index correspondant. En ce qui concerne l'élément qui est l'objet, nous obtenons la propriété de cette
url
objet et l'écrivons dans la propriété d'état
randomImg
. Après cela, le composant est rendu de nouveau et l'apparence de la page change.
Page d'application dans le navigateurProjet de cours terminé.
Résumé
Dans cette leçon, vous avez créé une application qui utilise ce que vous avez appris lors de la maîtrise de React. La prochaine fois, nous parlerons du développement d’applications React modernes et discuterons des idées de projet, de la mise en œuvre que vous pourrez pratiquer avec React.
Chers lecteurs! Avez-vous rencontré des difficultés lors de la réalisation de ce projet de cours?