Curso de Treinamento Reagir Parte 27: Projeto do Curso

Nesta parte da tradução do curso de treinamento do React, você é solicitado a criar um gerador de memes.

imagem

Parte 1: visão geral do curso, razões para a popularidade do React, ReactDOM e JSX
Parte 2: componentes funcionais
Parte 3: arquivos de componentes, estrutura do projeto
Parte 4: componentes pai e filho
Parte 5: início do trabalho em um aplicativo TODO, noções básicas de estilo
Parte 6: sobre alguns recursos do curso, JSX e JavaScript
Parte 7: estilos embutidos
Parte 8: trabalho contínuo na aplicação TODO, familiaridade com as propriedades dos componentes
Parte 9: propriedades do componente
Parte 10: Workshop sobre como trabalhar com propriedades e estilo de componentes
Parte 11: geração dinâmica de marcação e método de matrizes de mapas
Parte 12: workshop, terceira etapa do trabalho em uma aplicação TODO
Parte 13: componentes baseados em classe
Parte 14: workshop sobre componentes baseados em classe, status dos componentes
Parte 15: oficinas de saúde componentes
Parte 16: a quarta etapa do trabalho em um aplicativo TODO, manipulação de eventos
Parte 17: quinta etapa do trabalho em um aplicativo TODO, modificando o estado dos componentes
Parte 18: a sexta etapa do trabalho em um aplicativo TODO
Parte 19: métodos do ciclo de vida dos componentes
Parte 20: a primeira lição sobre renderização condicional
Parte 21: segunda lição e workshop sobre renderização condicional
Parte 22: sétima etapa do trabalho em um aplicativo TODO, baixando dados de fontes externas
Parte 23: primeira lição sobre como trabalhar com formulários
Parte 24: Segunda lição sobre formulários
Parte 25: Workshop sobre como trabalhar com formulários
Parte 26: arquitetura do aplicativo, padrão Container / Component
Parte 27: projeto do curso

Lição 45. Projeto do curso. Meme generator


Original

Então chegamos ao projeto do curso. Vamos criar um aplicativo que irá gerar memes. Vamos começar com o projeto create-react-app padrão criado usando este comando:

npx create-react-app meme-generator 

Aqui você pode encontrar informações sobre os recursos de seu uso.

No decorrer do trabalho neste projeto, você será solicitado a implementar algumas de suas partes e ler as explicações sobre elas. O projeto padrão já possui código padrão, localizado principalmente nos App.js index.js e App.js Você pode remover completamente esse código e tentar escrevê-lo por conta própria para testar a implementação dos mecanismos padrão dos aplicativos React.

Neste projeto, você está convidado a usar os seguintes 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 } 

Esses estilos podem ser incluídos no arquivo index.css já no projeto e index.css no arquivo index.js .

Portanto, com base na suposição de que os arquivos index.js e App.js estão vazios agora, você, como primeira tarefa, é convidado a escrever o código index.js , criar o componente mais simples no App.js e App.js -lo para index.js .

Aqui está o que deve aparecer no index.js :

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

Aqui importamos React e ReactDOM , estilos de index.css e o componente App . Depois disso, usando o método ReactDOM.render() , ReactDOM.render() que o componente App forma no elemento da página index.html com o identificador root ( <div id="root"></div> ).

Aqui está a App.js arquivo App.js :

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

Aqui é apresentado agora o componente funcional mais simples.

Nesta fase, o projeto se parece com o mostrado abaixo.


Aplicativo no navegador

Agora crie dois novos componentes, em dois arquivos cujos nomes correspondem aos nomes dos componentes:

  • O componente Header que será usado para exibir o cabeçalho do aplicativo.
  • O componente MemeGenerator , no qual as principais tarefas atribuídas ao aplicativo serão resolvidas. Nomeadamente, as chamadas para a API serão realizadas aqui. Os dados do aplicativo serão armazenados aqui.

Considerando as funções atribuídas a esses componentes, pense sobre o que deveriam ser.

Aqui está o conteúdo do arquivo Header.js :

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

Como esse componente será usado apenas para exibir o cabeçalho do aplicativo, nós o projetamos como um componente funcional.

Aqui está o código para o arquivo 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 

Aqui, levando em consideração as tarefas que devem ser resolvidas por meio do componente MemeGenerator , usaremos um componente baseado na classe. Há um construtor aqui no qual inicializamos o estado com um objeto vazio.

Após a criação desses arquivos, importamos-os para o App.js e retornamos a marcação do componente funcional do App , que usa instâncias desses componentes, sem esquecer que, se o componente funcional retornar vários elementos, eles precisarão ser envolvidos em algo. No nosso caso, esta é a <div> . Aqui está o código App.js atualizado:

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

Verifique a aparência do aplicativo.


Aplicativo no navegador

Agora vamos trabalhar no componente Header . Aqui vamos usar o elemento semântico HTML5 <header> . Essa tag conterá a imagem e o texto. Agora o código do arquivo Header.js ficará assim:

 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 

Veja como a aparência do aplicativo mudará.


Aplicativo no navegador

O título do aplicativo foi criado de acordo com os estilos index.js anteriormente no index.js . O trabalho no componente Header está concluído.

Continuaremos a lidar com o componente MemeGenerator . Agora você está convidado a inicializar independentemente o estado desse componente gravando os seguintes dados nele:

  • O texto exibido na parte superior do meme (propriedade topText ).
  • O texto exibido na parte inferior do meme (propriedade bottomText ).
  • Imagem aleatória (propriedade randomImage que precisa ser inicializada com o link http://i.imgflip.com/1bij.jpg ).

É assim que o código MemeGenerator.js será após a inicialização do 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 

Agora a aparência do aplicativo não é afetada.

Usaremos chamadas para a API, que retorna uma matriz de objetos contendo links para imagens, com base nos quais memes podem ser criados. Nesta fase do trabalho no projeto, você está convidado a implementar a seguinte funcionalidade no componente MemeGenerator :

  • Ligue para a API https://api.imgflip.com/get_memes/ .
  • Salve os dados disponíveis na resposta como uma matriz de response.data.memes na nova propriedade state ( allMemeImgs ).

Aqui, para tornar mais claro, um fragmento dos dados JSON retornados ao acessar 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        },        ….  ]  } } 

Resolvendo o problema exposto acima, é necessário levar em consideração o fato de estarmos falando de dados que o componente precisa no início do aplicativo.

Portanto, para carregá-los, recorreremos ao método do ciclo de vida do componentDidMount() . Aqui nós, usando o método fetch() padrão, chamaremos a API. Isso retorna uma promessa. Após carregar os dados, o objeto de resposta estará disponível para nós, extraímos a matriz de memes e a colocamos na nova propriedade de estado allMemeImgs , inicializada com uma matriz vazia. Como esses dados ainda não são usados ​​para formar algo exibido na tela, imprimiremos o primeiro elemento da matriz no console para verificar a operação correta do mecanismo de carregamento de dados.

Aqui está o código do componente MemeGenerator nesta fase do trabalho:

 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 

É isso que chega ao console depois de carregar os dados com êxito.


Aplicativo no navegador, saída para o console do primeiro elemento da matriz carregada

Observe que a imagem é descrita usando muitas propriedades. Usaremos apenas a propriedade url , que dá acesso ao link para baixar a imagem.

No início do curso, conversamos sobre como essa aplicação será exibida.


Meme generator

Em particular, sua interface possui alguns campos para inserir texto, que serão exibidos nas partes superior e inferior da imagem. Agora você está convidado a participar, com base no código atualizado do componente MemeGenerator mostrado abaixo, que difere do código acima desse componente, pois um formulário em branco é adicionado aqui, para criar alguns campos de texto, topText e bottomText . Lembre-se de que esses componentes devem ser gerenciados. Adicione os atributos necessários a eles. Crie um onChange eventos onChange esses campos nos quais você precisa atualizar as propriedades de estado correspondentes à medida que insere texto neles.

 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 

A propósito, preste atenção ao fato de que, para incluir um comentário no código retornado pelo método render() , o colocamos entre colchetes para indicar ao sistema que esse fragmento deve ser interpretado como código JavaScript.

Aqui está o que você deve obter nesta fase do trabalho no aplicativo:

 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 

Agora, a página do aplicativo será semelhante à mostrada abaixo.


Aplicativo no navegador

Embora apenas os campos com texto de ajuda sejam exibidos, a inserção de dados neles não leva a alterações na interface. Para verificar a operação correta dos mecanismos implementados aqui, você pode usar o comando console.log() .

Agora, trabalharemos por parte do aplicativo responsável por exibir o meme da imagem. Lembre-se de que agora temos uma matriz contendo informações sobre imagens que são planejadas para serem usadas como base de memes. O aplicativo deve, pressionando o botão Gen , selecionar aleatoriamente uma imagem dessa matriz e formar um meme.

Aqui está o código atualizado para o componente MemeGenerator . Aqui, no método render() , abaixo do código de descrição do formulário, existe um elemento <div> que inclui um elemento <img> que exibe uma imagem e alguns elementos <h2> que exibem rótulos. Os elementos <div> e <h2> são projetados usando os estilos que adicionamos ao projeto no início do trabalho nele.

 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 

Aqui está a aparência do aplicativo agora.


Aplicativo no navegador

Preste atenção ao fato de que a imagem que inicializou o estado é exibida aqui. Ainda não usamos imagens armazenadas na propriedade de estado allMemeImgs . Vamos tentar inserir algo nos campos de texto.


Aplicativo no navegador

Como você pode ver, os subsistemas de aplicativos responsáveis ​​por trabalhar com texto estão funcionando conforme o esperado. Agora resta apenas garantir que, ao pressionar o botão Gen , uma imagem aleatória seja selecionada da matriz com dados da imagem e carregada no elemento <img> , presente na página abaixo dos campos de entrada de texto.

Para equipar o aplicativo com esse recurso - execute a tarefa a seguir. Crie um método que é acionado quando você clica no botão Gen Esse método deve selecionar uma das imagens, informações sobre as quais são armazenadas na propriedade de estado allMemeImgs , e executar ações que permitem exibir essa imagem no elemento <img> localizado nos campos de entrada de texto. allMemeImgs que allMemeImgs armazena uma matriz de objetos que descrevem as imagens e que cada objeto dessa matriz possui uma propriedade url .

Aqui está o código que fornece uma solução para esse 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 

O botão Gen pode ser atribuído a um manipulador de eventos que ocorre quando você clica nele, como é o caso de qualquer outro botão. No entanto, como esse botão é usado para enviar o formulário, seria melhor usar o onSubmit eventos onSubmit formulário. Nesse manipulador, handleSubmit() , chamamos o método do evento event.preventDefault() entra nele para cancelar o procedimento padrão de event.preventDefault() formulário durante o qual a página é recarregada. Em seguida, obtemos um número aleatório no intervalo de 0 ao valor correspondente ao índice do último elemento da matriz allMemeImgs e usamos esse número para se referir ao elemento com o índice correspondente. Passando para o elemento que é o objeto, obtemos a propriedade desse url e a randomImg propriedade de estado randomImg . Depois disso, o componente é renderizado novamente e a aparência da página é alterada.


Página do aplicativo no navegador

Projeto do curso concluído.

Sumário


Nesta lição, você criou um aplicativo que usa o que aprendeu ao dominar o React. Da próxima vez, falaremos sobre o desenvolvimento de aplicativos modernos do React e discutiremos idéias de projetos, implementando as quais você pode praticar trabalhando com o React.

Caros leitores! Você encontrou alguma dificuldade ao concluir este projeto de curso?

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


All Articles