React Training Course Parte 27: Proyecto del curso

En esta parte de la traducción del curso de capacitación React, se le pide que cree un generador de memes.

imagen

Parte 1: descripción general del curso, razones de la popularidad de React, ReactDOM y JSX
Parte 2: componentes funcionales
Parte 3: archivos de componentes, estructura del proyecto
Parte 4: componentes principales y secundarios
Parte 5: inicio del trabajo en una aplicación TODO, los fundamentos del estilo
Parte 6: sobre algunas características del curso, JSX y JavaScript
Parte 7: estilos en línea
Parte 8: trabajo continuo en la aplicación TODO, familiaridad con las propiedades de los componentes
Parte 9: propiedades del componente
Parte 10: Taller sobre trabajo con propiedades de componentes y estilo
Parte 11: generación de marcado dinámico y método de matrices de mapas
Parte 12: taller, tercera etapa de trabajo en una aplicación TODO
Parte 13: componentes basados ​​en clases
Parte 14: taller sobre componentes basados ​​en la clase, estado de los componentes.
Parte 15: talleres de componentes de salud
Parte 16: la cuarta etapa de trabajo en una aplicación TODO, manejo de eventos
Parte 17: quinta etapa de trabajo en una aplicación TODO, modificando el estado de los componentes
Parte 18: la sexta etapa de trabajo en una aplicación TODO
Parte 19: métodos del ciclo de vida de los componentes.
Parte 20: la primera lección de representación condicional
Parte 21: segunda lección y taller sobre representación condicional
Parte 22: la séptima etapa de trabajo en una aplicación TODO, descargando datos de fuentes externas
Parte 23: primera lección sobre trabajar con formularios
Parte 24: Segunda lección de formularios
Parte 25: Taller sobre trabajo con formularios
Parte 26: arquitectura de la aplicación, patrón de contenedor / componente
Parte 27: proyecto del curso

Lección 45. Proyecto del curso. Generador de memes


Original

Entonces llegamos al proyecto del curso. Creemos una aplicación que genere memes. Comencemos con el proyecto estándar create-react-app creado con este comando:

npx create-react-app meme-generator 

Aquí puede encontrar información sobre las características de su uso.

En el curso del trabajo en este proyecto, se le pedirá que implemente algunas de sus partes usted mismo y luego lea las explicaciones sobre ellas. El proyecto estándar ya tiene un código repetitivo ubicado, en particular, en los App.js index.js y App.js Puede eliminar completamente este código e intentar escribirlo usted mismo para probarse en la implementación de los mecanismos estándar de las aplicaciones React.

En este proyecto, está invitado a usar los siguientes estilos:

 * {   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 } 

Estos estilos pueden incluirse en el archivo index.css que ya se encuentra en el proyecto e index.css en el archivo index.js .

Entonces, en base a la suposición de que los archivos index.js y App.js ahora están vacíos, usted, como primera tarea, está invitado a escribir el código index.js , crear el componente más simple en App.js y App.js a index.js .

Esto es lo que debería aparecer en index.js :

 import React from "react" import ReactDOM from "react-dom" import './index.css' import App from "./App" ReactDOM.render(<App />, document.getElementById("root")) 

Aquí importamos React y ReactDOM , importamos estilos desde index.css y el componente de la App . Después de eso, utilizando el método ReactDOM.render() , ReactDOM.render() lo que forma el componente de la App en el elemento de página index.html con el identificador de root ( <div id="root"></div> ).

Así es como se App.js archivo App.js :

 import React from "react" function App() {   return (       <h1>Hello world!</h1>   ) } export default App 

Aquí se presenta ahora el componente funcional más simple.

En esta etapa, el proyecto se parece al que se muestra a continuación.


Aplicación en navegador

Ahora cree dos componentes nuevos, en dos archivos cuyos nombres corresponden a los nombres de los componentes:

  • El componente Header que se usará para mostrar el encabezado de la aplicación.
  • El componente MemeGenerator , en el que se resolverán las tareas principales asignadas a la aplicación. A saber, las llamadas a la API se realizarán aquí. Los datos de la aplicación se almacenarán aquí.

Teniendo en cuenta qué funciones se asignan a estos componentes, piense en lo que deberían ser.

Aquí está el contenido del archivo Header.js :

 import React from "react" function Header() {   return (       <h1>HEADER</h1>   ) } export default Header 

Dado que este componente solo se usará para mostrar el encabezado de la aplicación, lo diseñamos como un componente funcional.

Aquí está el código para el archivo 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 

Aquí, teniendo en cuenta las tareas que se supone que deben resolverse mediante el componente MemeGenerator , utilizaremos un componente basado en la clase. Aquí hay un constructor en el que inicializamos el estado con un objeto vacío.

Una vez creados estos archivos, los importamos a App.js y devolvemos el marcado desde el componente funcional de la App , que utiliza instancias de estos componentes, sin olvidar que si el componente funcional devuelve varios elementos, deben estar envueltos en algo. En nuestro caso, esta es la <div> . Aquí está el código actualizado de App.js :

 import React from "react" import Header from "./Header" import MemeGenerator from "./MemeGenerator" function App() {   return (       <div>           <Header />           <MemeGenerator />       </div>   ) } export default App 

Verifique la apariencia de la aplicación.


Aplicación en navegador

Ahora trabajemos en el componente Header . Aquí usaremos el elemento semántico HTML5 <header> . Esta etiqueta contendrá la imagen y el texto. Ahora el código del archivo Header.js se verá así:

 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 

Así es como cambiará el aspecto de la aplicación.


Aplicación en navegador

El título de la aplicación está diseñado de acuerdo con los estilos previamente index.js en index.js . El trabajo en el componente Header ahora está completo.

Continuaremos MemeGenerator con el componente MemeGenerator . Ahora está invitado a inicializar independientemente el estado de este componente escribiendo los siguientes datos:

  • El texto que se muestra en la parte superior del meme (propiedad topText ).
  • El texto que se muestra en la parte inferior del meme (propiedad bottomText ).
  • Imagen aleatoria (propiedad randomImage que debe inicializarse con el enlace http://i.imgflip.com/1bij.jpg ).

Esto es lo que MemeGenerator.js código MemeGenerator.js después de inicializar el estado:

 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 

Ahora la apariencia de la aplicación no se verá afectada.

Utilizaremos llamadas a la API, que devuelve una matriz de objetos que contienen enlaces a imágenes, en función de los memes que se pueden crear. En esta etapa del trabajo en el proyecto, está invitado a implementar la siguiente funcionalidad en el componente MemeGenerator :

  • Llame a la API https://api.imgflip.com/get_memes/ .
  • Guarde los datos disponibles en la respuesta como una matriz de response.data.memes en la nueva propiedad de estado ( allMemeImgs ).

Aquí, para que quede más claro, un fragmento de los datos JSON devueltos al acceder a esta 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        },        ….  ]  } } 

Para resolver el problema planteado anteriormente, es necesario tener en cuenta el hecho de que estamos hablando de datos que el componente necesita al comienzo de la aplicación.

Por lo tanto, para cargarlos, recurriremos al método del ciclo de vida del componentDidMount() . Aquí, utilizando el método fetch() estándar, llamaremos a la API. Devuelve una promesa. Después de cargar los datos, el objeto de respuesta estará disponible para nosotros, extraemos la matriz de memes y lo allMemeImgs en la nueva propiedad de estado allMemeImgs , inicializado con una matriz vacía. Dado que estos datos aún no se utilizan para formar algo que se muestra en la pantalla, imprimiremos el primer elemento de la matriz en la consola para verificar el funcionamiento correcto del mecanismo de carga de datos.

Aquí está el código del componente MemeGenerator en esta etapa del trabajo:

 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 

Esto es lo que llega a la consola después de cargar con éxito los datos.


Aplicación en el navegador, salida a la consola del primer elemento de la matriz cargada

Tenga en cuenta que la imagen se describe utilizando muchas propiedades. Utilizaremos solo la propiedad url , que da acceso al enlace para descargar la imagen.

Al comienzo del curso, hablamos sobre cómo se verá esta aplicación.


Generador de memes

En particular, su interfaz tiene un par de campos para ingresar texto, que se mostrarán en las partes superior e inferior de la imagen. Ahora está invitado a tomar, según el código actualizado del componente MemeGenerator que se muestra a continuación, que difiere del código anterior de este componente en que se agrega un formulario en blanco aquí, para crear un par de campos de texto, texto topText e texto bottomText . Tenga en cuenta que estos deben ser componentes administrados. Agregue los atributos necesarios para ellos. Cree un onChange eventos onChange estos campos en el que necesita actualizar las propiedades de estado correspondientes a medida que ingresa texto en ellos.

 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 

Por cierto, preste atención al hecho de que para incluir un comentario en el código devuelto por el método render() , lo encerramos entre llaves para indicar al sistema que este fragmento debe interpretarse como código JavaScript.

Esto es lo que debe obtener en esta etapa del trabajo en la aplicación:

 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 

Ahora la página de la aplicación se verá como la que se muestra a continuación.


Aplicación en navegador

Si bien solo se muestran los campos con texto de ayuda, ingresar datos en ellos no conduce a cambios en la interfaz. Para verificar el funcionamiento correcto de los mecanismos implementados aquí, puede usar el comando console.log() .

Ahora trabajaremos en la parte de la aplicación responsable de mostrar el meme de la imagen. Recuerde que ahora tenemos una matriz que contiene información sobre imágenes que se planean utilizar como base de memes. La aplicación debe, al presionar el botón Gen , seleccionar aleatoriamente una imagen de esta matriz y formar un meme.

Aquí está el código actualizado para el componente MemeGenerator . Aquí, en el método render() , debajo del código de descripción del formulario, hay un elemento <div> , que incluye un elemento <img> que muestra una imagen y un par de elementos <h2> que muestran etiquetas. Los elementos <div> y <h2> están diseñados utilizando estilos que agregamos al proyecto al comienzo del trabajo en él.

 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 

Así es como se ve la aplicación ahora.


Aplicación en navegador

Preste atención al hecho de que la imagen que inicializó el estado se muestra aquí. Todavía no usamos imágenes almacenadas en la propiedad estatal allMemeImgs . Intentemos ingresar algo en los campos de texto.


Aplicación en navegador

Como puede ver, los subsistemas de aplicación responsables de trabajar con texto funcionan como se esperaba. Ahora solo queda asegurarse de que al presionar el botón Gen se seleccione una imagen aleatoria de la matriz con datos de imagen y se cargue en el elemento <img> , que está presente en la página debajo de los campos de entrada de texto.

Para equipar la aplicación con esta función, realice la siguiente tarea. Cree un método que se active cuando haga clic en el botón Gen Este método debe seleccionar una de las imágenes, cuya información se almacena en la propiedad de estado allMemeImgs , y luego realizar acciones que le permitan mostrar esta imagen en el elemento <img> ubicado debajo de los campos de entrada de texto. allMemeImgs en allMemeImgs que allMemeImgs almacena una matriz de objetos que describen las imágenes, y que cada objeto de esta matriz tiene una propiedad de url .

Aquí está el código que proporciona una solución a este problema:

 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 

Al botón Gen se le puede asignar un controlador de eventos que ocurre cuando hace clic en él, como es el caso con cualquier otro botón. Sin embargo, dado el hecho de que este botón se usa para enviar el formulario, sería mejor usar el onSubmit eventos onSubmit formulario. En este controlador, handleSubmit() , llamamos al método del evento event.preventDefault() entra en él para cancelar el procedimiento estándar de event.preventDefault() formularios durante el cual se recarga la página. Luego, obtenemos un número aleatorio en el rango de 0 al valor correspondiente al índice del último elemento de la matriz allMemeImgs y usamos este número para referirnos al elemento con el índice correspondiente. Volviendo al elemento que es el objeto, obtenemos la propiedad de esta url objeto y la escribimos en la propiedad de estado randomImg . Después de eso, el componente se vuelve a representar y la apariencia de la página cambia.


Página de aplicación en el navegador

Proyecto de curso completado.

Resumen


En esta lección, creó una aplicación que usa lo que aprendió mientras dominaba React. La próxima vez hablaremos sobre el desarrollo de aplicaciones modernas de React y discutiremos ideas de proyectos, implementando lo que puede practicar trabajando con React.

Estimados lectores! ¿Ha encontrado alguna dificultad al completar este proyecto del curso?

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


All Articles