Los memes son geniales, son una forma muy divertida de describir ideas y opiniones. Así que no es casualidad que elegí una aplicación de generador de memes como proyecto final en mi curso gratuito React en Scrimba. La aplicación funciona extrayendo una imagen aleatoria de meme de una API y colocando su texto sobre ella para crear su propio meme personalizado.
Entonces, en este artículo, te daré una guía paso a paso para crear la aplicación. Si alguna vez se confunde, también puede seguir estos pasos en el curso Scrimba, comenzando en esta conferencia.
Y luego, si le gusta mi estilo de enseñanza y está de humor para un desafío más difícil después de completar este tutorial, consulte mi próximo curso avanzado sobre Scrimba.
Nota: ya debe estar bastante familiarizado con algunos de los conceptos fundamentales de React, como componentes, estado, accesorios y métodos de ciclo de vida. Además, este tutorial no usa Hooks, pero en mi próximo curso cubriremos los Hooks en profundidad y practicaremos muchísimo su uso.
1. Crear el repetitivo y representar un componente de la aplicación
Lo primero que debemos hacer es crear el código repetitivo para la aplicación. Para hacer esto, importamos
React
y ReactDOM
utilizamos ReactDOM
para representar un componente llamado App
, que crearemos más adelante. Luego colocamos el App
componente en la 'raíz'. También importamos App
desde su archivo "./App"
, que crearemos en breve.// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
Luego creamos nuestro
App.js
archivo. En él, creamos un componente funcional llamado App
que, por ahora, devuelve un simple <h1>
. Luego lo exportamos. El <h1>
nos permite verificar que la aplicación se muestre correctamente en la pantalla.import React from 'react';
function App() {
return <h1>Hello world!</h1>;
}
export default App;
El resultado resultante es este:
2. Crear los componentes de encabezado y MemeGenerator
A continuación, creamos los componentes Header y MemeGenerator. El encabezado solo mostrará elementos, mientras que MemeGenerator llamará a la API y retendrá los datos en estado.
Comencemos creando el
Header.js
archivo. Dado que Header es un componente que solo se usa para mostrar, debe ser un componente funcional. Por ahora, el componente debería devolver un simple <h1>
. Después de crearlo, exportamos el encabezado.import React from 'react';
function Header() {
return <h1>HEADER</h1>;
}
export default Header;
A continuación, creamos el
MemeGenerator.js
archivo. Como el MemeGenerator
componente retendrá datos y realizará llamadas a una API, debe ser un componente de clase. Todavía necesitamos importar React, y dado que va a ser un componente de clase, también importaremos Component
(que es una importación con nombre ).
MemeGenerator necesita un estado
constructor()
que llame super()
y ya que estará en estado de espera, le agregamos un estado vacío ahora. Al igual que en el componente Encabezado, mostramos un sencillo <h1>
para comenzar. Luego exportamos MemeGenerator.import React, { Component } from 'react';
class MemeGenerator extends Component {
constructor() {
super();
this.state = {}; //empty state
}
render() {
return <h1>MEME GENERATOR SECTION</h1>;
}
}
export default MemeGenerator;
Ahora, importamos encabezado y MemeGenerator
App.js
y creamos una instancia de cada uno en nuestro componente de aplicación. Para mostrar los componentes correctamente, los envolvemos en a <div>
.import React from 'react';
import Header from './Header';
import MemeGenerator from './MemeGenerator';
function App() {
return (
<div>
<Header />
<MemeGenerator />
</div>
);
}
export default App;
3. Completando el componente Encabezado.
Para completar el
<Header>
componente, agregamos una imagen trollface insertando una <img>
etiqueta y configurando el src en la URL de la imagen. Luego agregamos una <p>
etiqueta con el nombre de nuestra aplicación y las envolvemos en la <header>
etiqueta semántica HTML5 .function Header() {
return (
<header>
<img
src='http://www.pngall.com/wp-content/uploads/2016/05/Trollface.png'
alt='Problem?'
/>
<p>Meme Generator</p>
</header>
);
}
Como el estilo está fuera del alcance de este curso, los estilos CSS ya se han creado y aplicado a la
<header>
etiqueta. El resultado es este:
Dicho esto, los alumnos siempre pueden jugar con el estilo y perfeccionar sus habilidades de CSS por sí mismos. Con el
<Header/>
ahora completo, el resto del desafío tendrá lugar en<MemeGenerator/>
4. Estado de inicialización
Ahora tenemos que inicializar el estado para que guarde un texto superior, un texto inferior y una imagen aleatoria, que ya se suministra.
Para hacer esto, construimos el objeto vacío que colocamos en
<MemeGenerator/>
cuando lo construimos originalmente. Inicializamos topText
y bottomText
como cadenas vacías y randomImg
como la URL proporcionada.class MemeGenerator extends Component {
constructor() {
super();
this.state = {
topText: '',
bottomText: '',
randomImg: 'http://i.imgflip.com/1bij.jpg'
};
}
}
5. Realizar la llamada API
A continuación, realizamos una llamada API a la URL proporcionada y guardamos los datos devueltos (que es una matriz que se encuentra
Cuando necesitamos cargar datos desde un punto final para usar en nuestro componente, un buen lugar para hacer la solicitud es el
response.data.memes
) en una nueva propiedad de estado llamada allMemeImgs
.Cuando necesitamos cargar datos desde un punto final para usar en nuestro componente, un buen lugar para hacer la solicitud es el
componentDidMount()
método del ciclo de vida. Tan pronto como se monte el componente, usamos la fetch()
función nativa para llamar a la URL proporcionada.componentDidMount() {
fetch("https://api.imgflip.com/get_memes")
}
Esto devuelve una promesa que convertimos en un objeto Javascript con el
.json()
método.componentDidMount() {
fetch("https://api.imgflip.com/get_memes")
.then(response => response.json())
}
Luego obtenemos la respuesta que nos es útil al extraer la matriz de memes
response.data
.componentDidMount() {
fetch("https://api.imgflip.com/get_memes")
.then(response => response.json())
.then(response => {
const { memes } = response.data
})
}
Ahora, guardamos los resultados en una nueva propiedad estatal llamada
allMemeImgs
. Para hacer esto, inicializamos allMemeImgs
como una matriz vacía.this.state = {
topText: '',
bottomText: '',
randomImg: 'http://i.imgflip.com/1bij.jpg',
allMemeImgs: []
};
Ahora, de vuelta
componentDidMount()
, establecemos el estado. Como no estamos interesados en cuál era el estado anterior, nos pusimos allMemeImgs
en memes.componentDidMount() {
fetch("https://api.imgflip.com/get_memes")
.then(response => response.json())
.then(response => {
const { memes } = response.data
this.setState({ allMemeImgs: memes })
})
}
Para asegurarnos de que funciona, tenemos
console.log
el primer elemento, que se parece a esto:
Aquí hay una descripción general de toda la
componentDidMount()
función.componentDidMount() { //ensure that data is fetched at the beginning
fetch("https://api.imgflip.com/get_memes") //call to URL
.then(response => response.json()) //turn promise into JS object
.then(response => {
const { memes } = response.data //pull memes array from response.data
console.log(memes[0]) // check data is present
this.setState({ allMemeImgs: memes }) // set allMemeImgs state
})
}
6. Crear el formulario de entrada
Ahora queremos crear un formulario que eventualmente permita al usuario ingresar los textos superior e inferior. Hacemos esto con una
<form>
etiqueta HTML y un simple <button>
que dice 'Gen'. Lo diseñamos con el CSS proporcionado previamente.render() {
return (
<div>
<form className="meme-form">
<button>Gen</button>
</form>
</div>
)
}
7. Agregar campos de entrada al formulario
A continuación, depende de nosotros agregar los dos campos de entrada (uno para el texto superior y otro para el texto inferior). El formulario debe ser controlado, por lo que necesitaremos agregar todos los atributos necesarios para que eso funcione. Crearemos el
onChange
controlador más tarde.
Creamos dos campos de entrada que tienen el tipo
text
y los atributos de nombre apropiados ( topText
y bottomText
). En lugar de usar etiquetas, usamos marcadores de posición: 'Texto superior' y 'Texto inferior'.
Por último, para que esto sea una forma controlada , establecemos el valor como igual al valor actual en
state
con {this.state.topText}
y {this.state.bottomText}
.render() {
return (
<div>
<form className="meme-form">
<input
type="text"
name="topText"
placeholder="Top Text"
value={this.state.topText}
/>
<input
type="text"
name="bottomText"
placeholder="Bottom Text"
value={this.state.bottomText}
/>
<button>Gen</button>
</form>
</div>
)
}
8. Crear el controlador onChange.
Ahora, creamos el controlador onChange, que actualizará el estado correspondiente en cada cambio del campo de entrada.
Primero, creamos una
handleChange()
función que recibe un evento.handleChange(event) {
}
Ahora, establecemos los
onChange
dos campos de entrada en igual handleChange
.<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>
Debemos recordar vincular el método en el constructor, un problema común para los desarrolladores de React.
constructor() {
super()
this.state = {
topText: "",
bottomText: "",
randomImg: "http://i.imgflip.com/1bij.jpg",
allMemeImgs: []
}
this.handleChange = this.handleChange.bind(this)
}
Para probar la nueva
handleChange()
función, agregamos un simple console.log
:handleChange(event) {
console.log("Working!")
}
Si está disparando correctamente, verá algo como esto:
Ahora para completar la
handleChange()
función. Para hacer esto, queremos extraer las propiedades de nombre y valor de event.target para que podamos obtener el nombre del estado que debemos actualizar ( topText
o bottomText
) y el valor que se escribe en el cuadro.handleChange(event) {
const { name, value } = event.target
}
Ahora los utilizaremos para actualizar el estado. Como no estamos interesados en cuál era el estado anterior, solo podemos proporcionar un objeto en el que establezcamos
[name]
el valor escrito en el campo de entrada.handleChange(event) {
const {name, value} = event.target
this.setState({ [name]: value })
}
9. Mostrar una imagen de meme junto al texto superior e inferior
Ahora queremos que la aplicación muestre una imagen de meme junto con el texto superior e inferior. Insertamos una
<img>
etiqueta debajo de <form>
y establecemos la randomImg
que inicializamos como fuente mediante el uso src={this.state.randomImg}
. Luego agregamos dos <h2>
etiquetas que muestran el texto correspondiente que también se guarda en estado. Todo esto está envuelto en un div
estilo con la meme
clase proporcionada previamente .<div className='meme'>
<img src={this.state.randomImg} alt='' />
<h2 className='top'>{this.state.topText}</h2>
<h2 className='bottom'>{this.state.bottomText}</h2>
</div>
Ahora podemos probar la aplicación escribiendo en los cuadros de texto. Como el estado se establece correctamente en cada pulsación de tecla, el texto que se muestra en la imagen cambia cada vez que escribimos.
10. Mostrar una imagen aleatoria de meme junto al texto superior e inferior
Ahora, necesitamos crear un método que muestre una imagen de meme que elija aleatoriamente de nuestra
Podemos dividir esta tarea en partes más pequeñas.
allMemeImgs
matriz cuando Gen
se haga clic en el botón. La propiedad de la imagen elegida en la matriz es .url
.Podemos dividir esta tarea en partes más pequeñas.
En primer lugar, configuramos los formularios
onSubmit
para que sean iguales al nombre de nuestro nuevo método, al que llamaremos handleSubmit()
.<form className="meme-form" onSubmit={this.handleSubmit}>
Ahora creamos la
handleSubmit()
función encima de la render()
función. Necesitamos evitar DefaultDefault en el evento, de lo contrario, el método intentará actualizar la página.handleSubmit(event) {
event.preventDefault()
}
También necesitamos unirnos
handleSubmit()
a nuestro constructor()
.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)
}
Ahora, necesitamos obtener un número aleatorio, obtener el meme de ese índice y establecerlo
randomImg
en el .url
elemento aleatorio.handleSubmit(event) {
event.preventDefault()
// get a random int (index in the array)
// get the meme from that index
// set `randomImg` to the `.url` of the random item I grabbed
}
Para obtener un número aleatorio, usamos
Math.floor(Math.random)
. Para asegurarnos de que sea uno de los índices en nuestra allMemeImgs
matriz, multiplicamos por la longitud de la matriz.const randNum = Math.floor(Math.random() * this.state.allMemeImgs.length);
Ahora nos ponemos
randMemeImg
a igual allMemeImgs
, con el índice de allMemeImgs
como el randNum
que acabamos de obtener. Luego agregamos .url
al final de la misma.const randMemeImg = this.state.allMemeImgs[randNum].url;
Ahora, todo lo que tenemos que hacer es actualizar el estado actualizando la propiedad randomImg con
randMemeImg
.this.setState({ randomImg: randMemeImg });
Nuestra
handleSubmit()
función completa se ve así: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 })
}
Generador de memes completado
Ahora hemos completado la aplicación del generador de memes y obtenemos una imagen diferente cada vez que presionamos el
Gen
botón, que luego se superpone con el texto que ingresamos.
Para avanzar en nuestro aprendizaje, podríamos jugar con código y ver si podemos mejorarlo o tratar de obtener imágenes de una API diferente. Para algunas prácticas realmente pesadas, incluso podríamos eliminar todo el código e intentar construirlo nuevamente desde cero.
Felicitaciones por seguir el tutorial y aprender todas las habilidades utilizadas en este proyecto.
Y si estás listo para ello, ¡mira mi próximo curso avanzado , ya que te llevará a un nivel profesional en React!
0 Comentarios