Transcrições
1. Introdução: Oi, eu sou Hunor, e hoje eu vou te ensinar como construir um jogo Tic-Tac-Toe com React. Se você não usou React antes, não se preocupe, nós vamos cobrir todos os conceitos básicos de React enquanto estamos construindo este jogo. Primeiro, eu vou falar sobre como quebrar este jogo em pedaços menores, em componentes, e como conectar esses componentes. Então vamos cobrir como tornar este jogo interativo, qual é o estado, e como detectar o vencedor no final do jogo. A única coisa que você precisa ter é algum conhecimento prévio de HTML, CSS e JavaScript, e depois deste curso, você será capaz de construir um jogo simples ou um site com React.
2. Como reduzir o jogo nos componentes: Vamos criar a nossa aplicação em React. Reagir é como uma biblioteca baseada em componentes. Então, primeiro, temos que dividir nossa aplicação em componentes. Mas o que é um componente e como quebrar um aplicativo? Um componente é como uma função. Se você pensar sobre isso, você escreve principalmente funções por duas razões. Uma delas é dividir sua lógica de aplicação em bits significativos menores. Uma função é basicamente um pedaço de código com um nome. Se alguém lê esse nome, esperançosamente, ele
saberia ou pelo menos ter uma boa idéia sobre o que a função faz. A segunda razão para escrever uma função é evitar a repetição. Se você se encontrar escrevendo as mesmas linhas uma e outra vez, então provavelmente você vai escrever uma função para isso e
chamá-la em vários lugares em vez de repetir as mesmas linhas. Vamos fazer a mesma coisa com os componentes. Mas antes de chegar lá, primeiro, precisamos de um componente inicial aquele que será injetado em HTML e que servirá como raiz para todo o resto do aplicativo. No nosso caso, este será o próprio componente TicTacToe. Tecnicamente, podemos parar aqui. Não é necessário ter vários componentes. Mas geralmente, se você tentar ter toda a sua lógica em um componente junto com todas as informações de layout, provavelmente, será muito longo e insustentável. Então vamos começar a quebrar nossa aplicação evitando a repetição. Há duas coisas muito obviamente repetindo neste aplicativo, as cruzes e os círculos. Há também um terceiro, que não é tão visual, por isso é fácil de perder. Mas se você olhar um pouco mais de perto, então você vê que esta grade consiste em nove quadrados. E os quadrados não têm muito a mostrar, mas você vai ver que seu comportamento é o mesmo. Então eles também vão ser realmente um bom candidato para um componente. Uma vez feito com repetição, podemos olhar para fora para partes do aplicativo que são mais ou menos independentes do resto do aplicativo. No nosso caso, se você jogar através deste jogo, então você acaba em uma tela de resultados. Claro, esta tela de resultados não é totalmente independente do resto
do jogo porque ele tem que saber se o jogo terminou, quem ganhou o jogo e como redefinir o jogo. Mas além disso, não precisa saber todos os detalhes. Não precisa saber qual é o status do segundo quadrado na terceira fila. Então, desta forma, é independente. Pode ser interpretado como uma função com propriedades. Então esses serão nossos componentes, mas é claro, essa não é a única maneira de quebrar um aplicativo. Uma maneira de verificar se fizemos um bom trabalho é verificar os nomes dos componentes. Se os nomes dos componentes são significativos e você pode
adivinhar mais ou menos o que o componente faz ou como ele se parece, então há uma boa chance de que nosso detalhamento seja bom.
3. Como escrever os primeiros componentes: Vamos começar a criar coisas. Para este tutorial, vamos usar CodePen, que é um editor web e plataforma de mídia social. Quando você cria algo no CodePen, ele será público para que outras pessoas possam vê-lo, possam comentar sobre ele, podem gostar, e se é realmente bom e os editores dos sites o vejam, então talvez eles o destacem e você pode veja a si mesmo na primeira página. Se você não usou o CodePen antes, então você pode se inscrever rapidamente usando sua conta do Twitter, GitHub ou Facebook. Uma vez que você está dentro, no canto superior esquerdo, você verá “Criar Caneta”, e isso está nos levando ao editor da Web. Então este é o seu editor aqui, você pode editar HTML, CSS e JavaScript e o melhor sobre isso é que uma vez que você editar algo, então o resultado aparecerá na tela de resultados imediatamente. Se você adicionar algum cabeçalho primário simples e parágrafo, então você verá o resultado no painel de resultados. Nós vamos usar Reagir e Reagir não faz parte do JavaScript padrão. É uma biblioteca externa. Felizmente para nós, no CodePen, você pode facilmente adicionar bibliotecas externas a um projeto. Vá para Configurações, selecione o painel JavaScript e procure Reagir. Depois de adicionar React, também
temos que adicionar algo chamado ReactDom e aqui você tem que ter cuidado que o número da versão do React e o número da versão do ReactDom têm que corresponder. Se esse não for o caso por alguns motivos
, confira o comentário abaixo deste vídeo. Temos que definir mais uma coisa aqui. Nós temos que definir um pré-processador JavaScript e este vai ser Babel no nosso caso. Em relação ao que é Babel, por que precisamos dele e o que é ReactDom. Vou explicar daqui a pouco, mas por enquanto, vamos guardar isto e estamos prontos para ir. Vamos escrever um pouco de JavaScript e vamos começar criando nosso primeiro componente. E isso pode ser surpreendente, mas um componente é basicamente uma função. Quando eu estava dizendo antes que a maneira como você quebra um aplicativo para um componente é o mesmo que quebrar uma lógica de aplicativo em funções. Bem, componentes estão mais perto de funções do que você poderia ter pensado. Um componente é uma função especial que está retornando algo que realmente se parece com HTML. Mas isso ainda não é HTML, ainda
estamos dentro do JavaScript e você pode estar se perguntando como isso está funcionando? Quero dizer, isso não é JavaScript. Você não pode adicionar tags HTML em JavaScript, e a resposta a esta pergunta é que, de fato, não
estamos usando JavaScript aqui. Isso não é JavaScript. Pelo menos não puro JavaScript. Lembre-se que definimos Babel como um pré-processador para JavaScript. Babel está transitando este código para JavaScript adequado. Em segundo plano, estamos tendo JavaScript adequado, mas estamos editando uma versão ligeiramente modificada do JavaScript, o que nos permite escrever tags HTML. Ou pelo menos algo que realmente se parece com tags HTML. Temos um componente React, mas na tela de resultados, ainda não o vemos. Isto é como ter uma função que nunca foi chamada. Estamos tendo uma função que está gerando um pedaço de HTML, mas não dizemos onde este HTML gerado deve pertencer e não é adicionado automaticamente à raiz do HTML. Temos que definir um ponto de entrada em HTML. Vamos apenas adicionar uma div simples, com um ID, e eu vou usar “app” como um ID, mas você pode apenas escrever qualquer outro nome, se quiser. Em JavaScript vamos usar o ReactDom. ReactDom é uma biblioteca de utilidade muito simples e seu único propósito é procurar o HTML, encontrar este ID, e substituir seu conteúdo pelo nosso componente. Se você fez tudo certo, então finalmente, temos um componente React dentro do nosso site e isso é realmente um ótimo começo. Antes de passarmos para a próxima seção, vamos adicionar rapidamente o esqueleto dos outros componentes que combinamos. Vamos apenas adicionar um componente Quadrado, um componente Cross e o componente Circle mais os componentes da tela de resultados. Estes componentes, por enquanto, serão componentes muito simples. Eles estão apenas retornando um pedaço de texto e eles não vão ser conectados com nossos componentes raiz. Eles estão apenas ficando no espaço e não fazendo nada, mas este é o nosso esqueleto de aplicação. Nós vamos conectar esses componentes em nossas próximas seções.
4. A grade: Em nossas lições anteriores, escrevemos nossos primeiros componentes React. Mas na tela de resultados, ainda
vemos apenas “Hello from React” no canto superior esquerdo, e nem estamos usando a maioria dos nossos componentes React. Nesta lição, vamos falar muito sobre CSS,
como adicionar estilo esses componentes, e como conectá-los, como incorporar o componente Square dentro do componente TicTacToe. Primeiro de tudo, vamos centralizar tudo. Agora, por padrão, tudo está no canto superior esquerdo. E este é um jogo, este não é um site normal, queremos centralizar tudo. Para centralizar tudo, vamos para nossa tag de nível mais alto e definir algumas propriedades CSS para ele. O nível mais alto agora é a nossa div dentro do HTML, que é o ponto de entrada do aplicativo. Ele já tem um ID, então vamos apenas usar isso dentro do CSS, e para centralizar as coisas, vamos usar CSS Flexbox. Se você ainda não usou CSS Flexbox antes, é muito bom para centralizar coisas e alinhar coisas uniformemente. Agora só vamos usá-lo para centralizar, e ele tem alguns nomes de propriedades muito estranhos como justify-content e align-items. Não é tão intuitivo que um seja para alinhar as coisas horizontalmente e outro é para alinhar as coisas verticalmente, mas funciona muito bem. Uma vez que adicionamos, tudo deve estar no meio da tela. Bem, tudo agora é apenas um texto dizendo, “Olá do React”, porque é tudo o que o componente TicTactoe está produzindo. Vamos mudar isso. Vamos substituir este texto inicial por nove instâncias do componente Quadrado. Você pode estar se perguntando como fazê-lo porque, TicTacToe componente está produzindo um pedaço de HTML, Quadrado componente também está produzindo um pedaço de HTML, mas o componente Square em si é apenas uma função. Então fazemos chamadas de função, e chamamos os componentes Quadrados como uma função? No React, você pode se referir a componentes, como se fossem tags HTML personalizadas. O que é realmente útil porque o componente Quadrado é necessário dentro da instrução de retorno de um componente TictaToe. Agora temos nove quadrados no componente TicTacToe, mas eles não aparecem como uma grade. Para corrigir isso, vamos atribuir alguma classe CSS para o recipiente principal do componente TictaToe. E isso é algo que é um pouco diferente do HTML. Como eu disse antes, isso não é HTML na verdade, ele só se parece com isso. Isso é chamado JSX, JavaScript XML, e tem algumas diferenças menores em comparação com HTML. Um deles é que você não pode usar a palavra-chave class, porque a palavra-chave class é reservada em JavaScript e tem alguns significados muito diferentes. Em vez de escrever classe, escrevemos ClassName. Para alinhar o conteúdo em uma grade, vamos usar grade CSS. Se você não usou a grade CSS antes ou CSS Flexbox, há um link abaixo deste vídeo que está explicando muito bem como eles funcionam. Então, com a grade CSS, estamos definindo, que queremos ter três colunas e três linhas, e queremos ter alguma lacuna entre elas. Agora parece um pouco melhor, mas os quadrados não se parecem com quadrados. Da mesma forma que anexamos uma classe para o componente TictaToe, vamos anexar uma classe quadrada para o componente Square, e vamos adicionar algum CSS. Aqui estamos corrigindo a largura, e a altura do componente, modo que ele vai parecer um quadrado, e nós também estamos centrando o conteúdo do quadrado da mesma maneira centralizamos todo o aplicativo, que CSS Flexbox. Agora temos nossos nove quadrados em uma grade, mas queremos ter alguma fronteira entre eles. Infelizmente, com a grade CSS, não
podemos definir a cor da borda. Vamos usar um pequeno truque aqui. Em vez de definir a cor da borda, estamos definindo a cor de fundo de toda a grade e,
em seguida, definindo a cor de
fundo dos componentes Quadrados para a cor de fundo do aplicativo inteiro. Dessa forma, parece que definimos a cor da borda da grade, mesmo que não tenhamos feito.
5. Qual Qual quadrado é o quê?: Temos nossa grade bonita, mas todos os quadrados no interior parecem iguais. Só para esclarecer, qual quadrado é qual, vamos dar-lhes uma identificação única. No React, você pode configurar instâncias de componente passando adereços para elas. Um adereços é algo como um atributo para uma função. Vamos dizer que é exatamente um atributo para nossa função componente. Vamos definir um atributo position para cada uma das nossas instâncias de componentes. Em Reagir, você pode transmitir uma propriedade da
mesma forma que você definiria um atributo para uma tag HTML. Podemos escrever posição igual e passar “0". Vamos usar índice baseado em zero aqui, porque mais tarde, quando especificamos algum valor adequado para os quadrados, vamos usar índice baseado em zero também. Também podemos transmitir um valor de uma maneira um pouco diferente. Em vez de usar aspas duplas aqui, também
podemos usar colchetes. Usando colchetes aqui, é chamado de ligação. É uma maneira muito mais poderosa de passar algumas propriedades para componentes filhos. Com colchetes, estamos basicamente abrindo uma janela para JavaScript. Inicialmente, estamos em terra JavaScript,
mas, em seguida, com JSX estamos começando a escrever algum HTML. Mas e se você quiser voltar para JavaScript dentro do HTML? Em seguida, usamos vinculação, com colchetes estamos abrindo uma janela para JavaScript, e o que quer que esteja dentro desses colchetes é avaliado como uma expressão JavaScript e o resultado disso será passado como uma propriedade. Neste momento não estamos usando todo o seu poder porque estamos apenas transmitindo um número. Mas também poderíamos usar algum cálculo matemático aqui, poderíamos chamar uma função aqui, ter uma expressão ternária... Qualquer coisa que seja uma expressão JavaScript válida, podemos usar aqui. Há também uma pequena diferença aqui entre passar um valor entre colchetes e passar um valor entre aspas duplas. Se você passar um número entre aspas duplas, ele será um texto, ele será interpretado como uma string. Por outro lado, se você está passando um número entre colchetes, ele vai ficar um número. Vamos para o outro lado das coisas e vamos usar esta propriedade passada no componente Square. Como eu disse, propriedades em componentes React é passado como um atributo para a função componente. Mas em vez do primeiro atributo desta função simplesmente se tornando posição, o primeiro atributo será um objeto genérico para todas as propriedades do componente. Isso pode ser confuso para componentes que têm apenas uma propriedade. Esteja ciente de que o primeiro atributo ainda vai ser um objeto, que tem um atributo agora, a posição. Aqui podemos pegar todo o objeto adereços e referir-se ao atributo position do objeto adereços, ou podemos decomposição este objeto adereços imediatamente na assinatura função. Temos este atributo de posição agora, passado. Como é que a usamos? Basicamente, o que queremos alcançar é em vez de mostrar “Quadrado”, queremos mostrar o número da posição dentro deste componente. O que podemos fazer neste caso? Queremos usar uma variável JavaScript dentro do JSX. Podemos fazer a mesma coisa novamente, o que acabamos de fazer antes com a passagem de uma variável como uma propriedade. Podemos usar a ligação. Novamente, estamos usando colchetes e dentro colchetes nós apenas usar a variável position. Depois de tudo isso, devemos ver uma identificação única dentro de cada quadrado, dentro de nossa grade.
6. As peças em mudança: Em nossa lição anterior, conseguimos passar um ID único para cada quadrado, mas dentro dos quadrados queremos ter círculos em cruzes com base no progresso do jogo. Isto é algo que vai ser dinâmico. Inicialmente, cada quadrado vai ficar vazio e uma vez que você clicar neles eles devem mostrar um círculo ou uma cruz. Em React tudo o que é dinâmico, tudo o que está mudando ao longo do tempo deve ser definido em um estado. O estado junto com os adereços são os dois principais fatores que moldam um componente, mas enquanto os adereços estão sendo
transmitidos pelos pais para que eles saem do componente, o estado é uma coisa interna. O que está mudando aqui? duas coisas principais que estão mudando ao longo do jogo. Em cada turno, um quadrado recebe um novo valor. Ele recebe um círculo ou uma cruz. O estado dos quadrados é definitivamente algo que precisamos manter o controle. A outra coisa que está mudando ao longo do jogo é o jogador. Depois de cada turno está mudando de círculo para cruz ou de cruz para círculo. Estas serão as duas partes principais do nosso estado. Agora devemos discutir onde definir o estado. Em relação ao jogador, faz sentido defini-lo no nível superior porque não tem nada a ver com quadrados, círculos ou cruzes. É o estado de todo o jogo. Mas em relação ao estado dos quadrados, pode
parecer lógico defini-los nos quadrados. Cada quadrado seria responsável por seu próprio estado interno. Eles saberiam se deveriam estar vazios ou se deveriam conter uma cruz ou um círculo. Mas há um grande problema arquitetônico com este aqui. Os quadrados conhecerão seu próprio estado interno, mas ninguém saberia todo o estado de toda a grade. Isso é devido à forma como a comunicação funciona entre os componentes no React. Reagir funciona de cima para baixo. Um componente de nível superior, como o componente TicTacToe, pode passar propriedades para os componentes de nível filho como o componente Quadrado, mas não funciona o contrário. O componente Quadrado, as crianças não podem passar propriedades para seus pais. Do ponto de vista filho, o componente Quadrado pode ter acesso ao estado do componente TictaToe porque o componente TictaToe pode transmiti-lo como uma propriedade, mas não está funcionando ao contrário. O componente TicTacToe não pode ter acesso
ao estado do componente Quadrado porque o componente Quadrado simplesmente não pode transmiti-lo. Vamos ver se há uma solução aqui. Podemos usar retornos de chamada para relatar certo progresso da criança para o pai, mas isso é um pouco diferente. Com adereços, você está passando uma propriedade. Estás a expor algumas das tuas variáveis aos teus filhos. Mas com retornos de chamada, são chamadas de função. Eles são como um evento. Não é como compartilhar suas variáveis. Uma vez que descobrimos como a comunicação funciona entre os componentes e como o estado e os adereços funcionam juntos, provavelmente
podemos concordar que se você precisar de certa lógica, que é detectar se o jogo terminou e diz qual jogador ganhou o jogo, então precisamos ter o estado de cada quadrado em um lugar comum. Isso vai ser um nível maior no componente TicTacToe. Agora concordamos que vamos ter todo o nosso estado
no componente de nível superior e este é um padrão bastante comum. Normalmente, os componentes de nível superior são os inteligentes. Eles geralmente têm a lógica e o estado, mas eles não são tão visuais enquanto, por outro lado, os componentes de nível inferior geralmente recebem todos os seus valores verdadeiros adereços e eles são aqueles que estão tendo para representações
visuais do , mas o estado em geral nem sempre tem que estar no nível superior. Tem de ser, de facto, tão baixo quanto possível, mas ainda tão elevado quanto necessário. Vamos ter outro exemplo para isso. Vamos dizer que você é realmente bom no desenvolvimento de jogos e você criou um site cheio de jogos. Ele irá conter um aplicativo TictaToe, ele irá conter um Tetris ou Mine Sweeper etc. Neste caso, se você estiver tendo o componente de nível superior, que é a página inteira, ele não precisa saber o estado interno do Jogo do Tictactoe. Nós ainda podemos ter estados de nível inferior individualmente para cada jogo e no nível superior, talvez não haja nenhum estado em tudo.
7. Primeira tentativa para adicionar um estado: Na lição anterior, tínhamos muita teoria sobre como o estado funciona e
como os componentes da aplicação podem ser conectados com adereços. Vamos começar a definir o nosso estado. Como combinamos. Vamos passar para o componente Tic Tac Toe e definir um estado para o jogador e para as posições. As posições por agora, vai ser uma matriz que irá conter o valor de cada quadrado na grade. Mas antes de definir os estados, vamos apenas ter algumas constantes para os possíveis valores dos quadrados. Vamos definir os estados. Por enquanto, vamos definir os estados como variáveis simples. Mais tarde, vamos ver que os estados têm que ser algo especial,
algo mais do que uma simples variável. Mas, por enquanto, vamos manter as coisas simples. Uma vez que definimos o estado da posição que está contendo dois valores de cada quadrado, vamos apenas passar sobre este valor para cada quadrado. Nós simplesmente fazê-lo da mesma maneira que estamos passando em uma posição atributos para o componente. Estamos adicionando um novo adereço aqui. Vamos apenas chamá-lo de valor, que pode conter círculo vazio ou cruz. Só para tornar este exemplo um pouco mais interessante, em vez de ter uma grade vazia como um estado inicial, vamos apenas ter algumas cruzes e círculos aleatórios neste estado. Ok, então agora estamos transmitindo um valor para cada quadrado, mas é claro, nós também temos que mudar o componente Quadrado para refletir esses valores. O componente Quadrado deve conter um círculo ou um componente cruzado dependendo desse valor. Para conseguir isso, vamos usar uma expressão JavaScript. Isto pode ser um pouco confuso no início, mas esta é simplesmente uma operação booleana. Se a primeira parte antes do && for falsa, a segunda parte dessa expressão não será avaliada. Simplesmente falso é retornado. Mas se a primeira parte for verdadeira, então a segunda parte será o resultado dessa expressão. Neste caso, isso seria círculo ou cruz. Felizmente para nós, se uma expressão é falsa, então reaja com simplesmente ignorá-la. Nesta configuração, apenas um círculo ou uma cruz deve aparecer. Nunca ambos e se o valor for inicial, então este quadrado deve permanecer vazio. Agora em nossa grade, já devemos ver alguns círculos e cruzes
dependendo do nosso estado inicial ou pelo menos o texto de espaço reservado para ele. Mas antes de mudar o texto do espaço reservado em círculos reais e cruzes, vamos parar por um segundo aqui, e vamos pensar em como esse aplicativo funcionará.
8. Um estado que pode mudar: Antes de seguirmos em frente, vamos parar um pouco e ver como esse aplicativo vai funcionar. Até agora, temos nossa função que está gerando nosso estado inicial. Após a renderização inicial, o estado do jogo mudará com base em nossa interação. Claro, queremos refletir essas mudanças no layout. A maneira como React está lidando com isso é retornando o componente inteiro e ele irá re-renderizar o componente inteiro executando a mesma função. Esta é uma situação engraçada aqui, porque estamos executando a mesma função duas vezes e estamos esperando um resultado diferente. Eu gosto de destacar aqui que esta é apenas uma função JavaScript normal além de retornar algo que se parece com HTML, não
há nada mágico aqui. Se você apenas olhar para esta função, fica bem claro que se você está tendo o estado neste formato, esta função irá gerar o mesmo resultado, não importa quantas vezes nós executá-lo. O que podemos fazer para consertar isso? Precisamos de um estado que possa devolver o último valor que atribuímos a ele. Portanto, precisamos armazená-lo fora deste componente. Em React, a fim de resolver este problema, eles introduziram React Hooks. Um dos Hooks é chamado USEstate e é exatamente para este problema. Nós o gancho USEstate, podemos armazenar um estado fora
do componente e ele sempre nos dará de volta o valor mais recente. A primeira vez que estamos executando esta função, podemos inicializar o estado com um valor que estamos passando como um atributo. Este atributo será obviamente ignorado em todas as chamadas futuras assim que o valor já estiver armazenado. O gancho USEstate retorna uma matriz de dois itens. O primeiro item é o próprio estado. Se você apenas executar a função pela primeira vez, então ele basicamente retorna nosso estado inicial. Mas se você estiver executando a função devido a uma re-renderização, então ele retornará o valor mais recente do estado. O segundo item que o gancho USEstate é devolvido para nós é uma função e esta função pode ser usada para alterar o estado. No futuro, para qualquer interação, se você precisar mudar o estado, precisamos chamar essa função e nós não só chamamos essa função para alterar o estado, mas também está acionando automaticamente a re-renderização do componente. Então, mudando o estado, nós também rerenderizamos o componente, que é claro que refletimos a mudança de estado onde acabamos de ter.
9. Círculos e cruzamentos: Esta lição vai ser divertida, e é um ovo de Páscoa porque não tem que fazer nada que reaja. Neste, vamos codificar imagens. Vamos desenhar círculos vetoriais e cruzes. Se você alguma vez verificar o código-fonte de uma imagem, então você provavelmente percebe que eles são super complicados e você simplesmente não pode obter nada fora dela. Mas nós vamos usar SVGs, e SVGs não são tão complicados, especialmente se você está indo apenas para usá-lo para algo simples. A coisa boa sobre SVGs é que eles são baseados em XML, e desde HTML5, eles são parte da sintaxe HTML. Você pode simplesmente incorporar um SVG dentro do HTML. Você não precisa usar uma imagem externa e não precisa carregá-la no HTML. Você pode simplesmente escrevê-lo como parte do seu HTML. Como eles se parecem? Primeiro de tudo, cada SVG é enrolado em uma tag SVG. Na tag SVG, você pode definir a largura e a altura do SVG junto com a ViewBox. O ViewBox está definindo seu sistema de coordenadas. No nosso caso, vamos definir que o SVG começa no canto superior esquerdo com a coordenada -50 -50, e a largura e a altura do SVG Canvas serão 100 cada. Assim, o centro da imagem será zero, zero. Você pode notar que a altura e a largura que definimos no SVG e a altura e a largura que definimos no ViewBox são as mesmas, mas isso não é algo que é obrigatório. A altura e a largura definidas como atributos
na tag SVG serão o tamanho real do SVG. Enquanto o ViewBox está definindo a tela em que podemos desenhar. Cada coordenada dentro deste SVG se relacionará com esta tela. O ViewBox está definindo um tamanho interno a partir da perspectiva dos itens de imagem. Se o tamanho real da imagem e o tamanho definido pela ViewBox não corresponderem, então a imagem será simplesmente reduzida ou dimensionada. Agora temos uma tela. Vamos desenhar algo nele. Vamos começar com um componente Circle porque isso é apenas um círculo. Podemos simplesmente adicionar uma tag circular e dizer que o centro dela estará no centro
da tela e o raio será de 40 pixels. Você notará que isso renderizará um círculo preto. Isso não é exatamente o que queremos, mas como SVGs são parte do HTML, também
podemos usar CSS para estilizá-lo. Antes do estilo, vamos apenas definir o componente Cross também. Nós simplesmente definimos duas linhas definindo suas coordenadas iniciais e suas coordenadas finais. Agora, se você está se perguntando, o que você fez de errado porque você está cruzes não aparecendo, isso é completamente normal. Por padrão, a largura da linha é zero. Temos que mudar isso no CSS. Vamos definir algum estilo para SVGs em geral. Aqui podemos definir uma largura de linha, que é chamado de largura de traçado. Também podemos alterar a cor definindo a propriedade traçado. Vamos também remover o enchimento, que é automaticamente preto no caso do círculo. Digamos que preencha: nenhum. Se você quiser ser chique, nós também podemos alterar a propriedade traço-linecap, que tornará nossas terminações de linha arredondadas. Se você quiser ter cores diferentes para os círculos e as cruzes,
então, já que estamos em HTML agora, você pode simplesmente anexar uma classe CSS para a cruz ou o círculo, em
seguida, definir uma cor diferente para eles com base na classe CSS. Agora temos esses círculos e cruzes de boa aparência. Para terminar este jogo, vamos seguir em frente com uma das partes mais essenciais, que é a interação.
10. Interação: Ok, olhando bem, mas até agora tudo ainda é estático e este é um jogo então você quer adicionar alguma interação, então devemos anexar um manipulador de eventos para os quadrados. Mas, infelizmente, no React, não
podemos anexar manipuladores de eventos em níveis de componente. Temos que anexar manipuladores de eventos para as tags HTML reais. No nosso caso, o mais próximo que podemos chegar é a tag de contêiner dentro de um componente Quadrado. Mas há um pequeno problema aqui, nós concordamos que vamos ter o estado dentro de um componente TicTacToe, mas este manipulador de eventos agora está no componente Square. Temos que encontrar uma maneira agradável que o componente Quadrado, pode definir o estado. Uma idéia poderia ser que, juntamente com a passagem do estado para o componente Square, nós também poderíamos passar sobre a função setState, e desta forma, o componente Square poderia mudar o estado em si. Mas, juntamente com a mudança do estado da grade, também
queremos mudar o estado do jogador. Claro, nós também poderíamos passar para o jogador para o componente Quadrado e o componente Square poderia mudar todo o estado porque ele vai saber tudo. Mas isso é contra a idéia de ter o componente Quadrado o mais simples possível, e se você pensar sobre isso, o jogador não tem nada a ver com o componente Quadrado realmente. O jogador pertence à lógica principal que deve ser definida no componente TicTacToe. Em vez de passar tudo, o que vamos fazer é passar um retorno de chamada. Um retorno de chamada é quando você está passando em uma função, então você está esperando que a função é chamada em determinados eventos. No nosso caso, o componente TicTacToe passará uma função e o componente Quadrado chamaremos essa função uma vez que foi clicado. A coisa boa sobre isso é que a função que estamos passando é definida no componente TicTacToe,
então, ele tem acesso total a tudo dentro do componente TicTacToe junto com o estado, e o player e enquanto um componente Quadrado tem acesso a nenhum deles, ele ainda pode chamar a função. No componente TicTacToe, vamos escrever uma função que recebe qual quadrado foi clicado, e ele muda o estado atualizando a grade e alterando o player. Então vamos passar esta função para cada um dos quadrados, como uma propriedade. É importante notar aqui que não estamos chamando a função aqui. Estamos apenas passando uma referência para a função, assim como poderíamos fazer com qualquer outra variável. O único lugar onde vamos chamar esta função será dentro do componente Square, que vai ter acesso a ele porque nós apenas passá-lo como uma propriedade. Dentro do componente Quadrado, podemos definir um manipulador de eventos para o evento clique, e este manipulador de eventos requer uma função. Será tentador usar a função que acabou de ser passada a partir do componente TictaToe, mas não é tão fácil. A função transmitida pelo componente TicTacToe requer um atributo position. O que podemos fazer é que podemos definir um manipulador de eventos intermediário no componente Square, que é chamado uma vez que o quadrado é clicado,
em seguida, ele vai transferir para chamar para o nosso callback. Neste manipulador de clique intermediário, podemos facilmente passar sobre o
atributo position porque o componente Square sabe a posição. Também podemos adicionar alguma lógica extra aqui, por exemplo, se o quadrado não estiver vazio, então vamos ignorar o clique. Uau, então fomos longe, quero dizer, agora você pode realmente jogar este jogo. É interativo, parece bom. Tudo está no lugar, exceto uma última parte, anunciando o vencedor.
11. Como detectar o vencedor: Estamos muito perto de terminar este jogo agora, mas ainda não sabemos se o jogo terminou, se alguém ganhou o jogo ou se é um empate. A fim de fazer isso, vamos escrever uma função utilitário, que vai ser uma função JavaScript simples, e então vamos ver como essa função JavaScript simples está se encaixando em sua lógica de aplicação. Para fazer esse cálculo, essa função precisaria do estado do jogo, precisaria do valor de cada quadrado. Mas além
disso, seria uma função JavaScript simples, não
é nada Reagir específico, é apenas uma função que recebe uma matriz de nove valores e devolve um resultado. Então, detectar se alguém ganhou o jogo é verificar se há três círculos ou três cruzes seguidas, em uma coluna, ou de uma forma diagonal. Basicamente, temos que verificar os itens específicos nesta matriz de nove itens. Se você quiser verificar se a primeira linha está cheia de círculos, então vamos verificar se o primeiro, segundo e terceiro item nesta matriz é um círculo. Se eu estiver indo para isso a segunda linha, a segunda linha, então nós vamos verificar se o quarto, quinto e sexto item nesta matriz é um círculo e assim por diante. É um cheque super simples. É basicamente algumas condições se, se esses valores são todos círculos, então a função retorna que o vencedor é círculo. Se esses valores são todos cruzes, então ele vai retornar que o vencedor é uma cruz. Se a função verificou que ninguém ganhou o jogo, então ainda há duas opções. O jogo ou terminou e é um empate, ou o jogo ainda está acontecendo. Detectar um empate neste ponto é simplesmente verificar se todos os quadrados já têm um valor, então não há mais movimento possível. Neste caso, vamos retornar que “É um empate”. A única opção restante é que ninguém ganhou o jogo, não
é um empate, então o jogo ainda está acontecendo. Neste caso, simplesmente não devolvemos nada. OK, então nós temos esta função e esta é uma função utilitário, então provavelmente nós podemos apenas tê-lo em algum lugar fora dos componentes React, mas nós também podemos tê-lo no componente TicTacToe porque TicTacToe componente está manipulando o principal lógica e é o único lugar onde essa função é necessária, então você pode decidir isso. Como isso se encaixa em nossa aplicação? O ciclo de vida desses aplicativos Tic-Tac-Toe até agora é que estamos renderizando a coisa toda como um estado inicial, então uma vez que você está clicando em um dos quadrados, então a coisa toda é re-renderizada. Isso continua em um loop até você continuar clicando em quadrados. Detectar o vencedor pode vir após cada clique, para que ele possa fazer parte do manipulador de eventos depois de clicar em um quadrado. Neste caso, podemos ter um estado extra para o vencedor. Poderíamos armazenar o vencedor em um estado, então com base nisso, poderíamos renderizar uma tela de resultados. A outra opção vem percebendo que o vencedor é um estado derivado. Ele vem com base nos estados já existentes, então não precisamos ter uma parte separada do estado para armazenar algo que já podemos descobrir do resto do estado. Mas se nós não estamos armazenando no estado, então onde nós temos isso? Precisamos saber se alguém ganhou o jogo na renderização, porque nesse caso, vamos renderizar o componente Resultado. Então, podemos simplesmente adicionar alguma lógica extra entre obter o estado do gancho React, que está contendo o valor dos quadrados e renderizando a grade com base nesse estado. Qualquer coisa que você escrever nesta função, como
discutimos, será reexecutado com cada renderização. Quando você está re-renderizando este componente, ele irá detectar se alguém ganhou o jogo e, em seguida, ele pode tomar uma decisão de renderizar a tela de resultados com base nisso. Portanto, estas são duas opções e sinta-se livre para ir com o que você preferir. No final, ambos terão uma variável vencedora que
conterá se o círculo ou a cruz ganhou o jogo, ou se é um empate ou não conterá nada e isso indicará que o jogo ainda está ligado.
12. E o Winner é ...: Neste último capítulo, vamos criar nossa tela de resultados. Anteriormente, já conseguimos derivar nosso estado em uma variável vencedora, que conterá, se o jogo foi ganho pelo círculo, a cruz, ou ninguém ganhou o jogo e o jogo ainda está ligado. A tela de resultados chegará ao componente TicTacToe porque o componente TicTacToe é aquele que está montando a lógica principal do jogo. No layout, o resultado apareceria no topo da grade, mas tecnicamente em HTML, ele vai estar próximo a ele porque a grade já tem algum CSS distinto, que é específico para a grade, e nós não queremos ter a tela de resultados dentro disso porque a tela de resultados pareceria algo completamente diferente. Mas agora temos duas tags HTML dentro dos resultados dos componentes TicTacToe. E em React, não
podemos ter isso. Reagir sempre tem que retornar uma tag HTML como resultado. Mas podemos corrigir isso facilmente porque essa tag de resultado pode ter um conteúdo e esse conteúdo pode ter várias tags HTML. É exatamente o mesmo que nossa grade anterior está contendo nove quadrados. Vou simplesmente adicionar uma tag wrapper como um contêiner para o componente Tic Tac Toe, que teria tanto a grade quanto a tela de resultados. Mas agora tanto a tela de resultados quanto a grade estão aparecendo sempre e nós só queremos ter a tela de resultados no caso de alguém ganhar o jogo ou se é um empate. Queremos renderizar esta tela de resultados condicionalmente com base no atributo vencedor. Podemos fazer o mesmo truque que fizemos no componente Quadrado quando
renderizamos um círculo ou uma cruz com base no valor do quadrado. Agora, com base no valor do vencedor, vamos renderizar o resultado. Como combinamos, se o vencedor estiver vazio, significa
que o jogo ainda está de pé. Isso também significa que, se você estiver usando essa condição, que se o jogo ainda estiver ativado, a tela de resultados não aparecerá. Conseguimos esconder a tela de resultados durante o jogo. Nós também queremos torná-lo inteligente o suficiente para saber quem ganhou o jogo porque agora ele simplesmente diz resultado, ele não diz qual é o resultado. Para fazer isso, precisamos passar o atributo vencedor para este componente da
mesma forma que passamos atributos para os quadrados. Então, do outro lado, no componente de resultados, precisamos pegar essa variável e podemos ter alguma renderização condicional com base em seu valor. Por padrão, isso apareceria abaixo da grade. Mas se você quiser tê-lo no topo da grade, então podemos adicionar algum estilo CSS e com isso, podemos configurá-lo para
posicionar absoluto e definir algumas outras propriedades para torná-lo um pouco mais agradável. Depois de terminar o jogo, o vencedor foi anunciado, o que vem a seguir? Se você quiser jogar outra rodada, então você tem que atualizar a página. Em vez disso, também podemos definir uma função de reset que iria redefinir o nosso estado. Como estamos redefinindo nosso estado, temos que definir isso
no componente TictaToe porque é aquele que está tendo acesso ao estado. Mas depois disso, podemos passar essa função de reset para o nosso componente de tela de resultados. Este vai ser mais um retorno de chamada, exatamente como estávamos passando um retorno de chamada para o componente Quadrado, que foi usado quando você clica no quadrado. Este será usado se você clicar no botão de reinicialização na tela de resultados. Vou apenas passar esta função como uma propriedade e dentro do componente da tela de resultados, se você definir um botão para redefinir, então podemos simplesmente passar esta função para o manipulador de eventos onClick deste botão, sem qualquer evento de nível médio manipuladores no meio. A diferença entre este e o outro no componente Quadrado é que aquele no componente Quadrado precisava de alguma propriedade extra para ser passada para a função de componentes TicTacToe. Mas esta, as funções de reset não precisa de nenhuma propriedade, por isso pode ser simplesmente chamada, pode ser simplesmente vinculada ao manipulador de eventos deste botão. E isso é tudo o que é. Agora temos um jogo que você pode jogar, a tela de resultados aparecerá e assim que você terminar, você pode redefinir o jogo e jogar outra rodada.
13. Conclusão: Parabéns. Agora eu tenho um jogo
Tic-Tac-Toe, espero que você também terá uma compreensão muito melhor de como Reagir funciona. Mas se você ainda tem algumas perguntas ou algumas partes ainda estão confusas para você, então sinta-se livre para me contatar aqui ou no CodePen. Claro, este jogo está mal terminado. Poderíamos ter muito mais a ele, mas isso teria feito um tutorial muito mais longo. Em vez disso, você pode encontrar um link abaixo deste vídeo que está explicando alguns recursos adicionais, como como adicionar animação a ele, ou como definir uma lógica de computador e jogar contra o computador. Sinta-se livre para seguir em frente com este projeto, e quando terminar não se esqueça de compartilhá-lo. Mal posso esperar para ver.