Cours de formation React Partie 27: Projet de cours

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

image

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 composants
Partie 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 cours

Leçon 45. Projet de cours. Générateur de mème


Original

Nous 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;  /* fallback for old browsers */   background: -webkit-linear-gradient(to right, #2a0845, #6441A5);  /* Chrome 10-25, Safari 5.1-6 */   background: linear-gradient(to right, #2a0845, #6441A5); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ } 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 { /* Chrome/Opera/Safari */ font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input::-moz-placeholder { /* Firefox 19+ */ font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-ms-input-placeholder { /* IE 10+ */ font-family: VT323, monospace; font-size: 25px; text-align: cen } .meme-form > input:-moz-placeholder { /* Firefox 18- */ 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 navigateur

Cré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 navigateur

Maintenant, 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 navigateur

Le 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ème

En 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 navigateur

Bien 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 navigateur

Faites 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 navigateur

Comme 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 navigateur

Projet 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?

Source: https://habr.com/ru/post/fr447136/


All Articles