Começando com a biblioteca Javascript React
Publicados: 2022-02-16Se você passa algum tempo no mundo WordPress, provavelmente já se deparou com Zac Gordon. Zac é um professor entusiasmado e encantador que se concentra em Javascript no WordPress. Ele emprestou a frase "Learn Javascript Deeply" de Matt Mullenweg e a transformou em seu slogan pessoal.
Nos últimos anos, Zac produziu videoaulas, conferências online, palestras ao vivo e podcasts que focam em ensinar você a usar Javascript no WordPress.
Tenho o prazer de dizer que estamos trabalhando com Zac em um livro, "React Explained". React é a biblioteca que a equipe do WordPress escolheu para o novo editor do Gutenberg. Eles não estão sozinhos - tanto o Drupal quanto o Magento também escolheram o React.
Zac está twittando ao vivo seu progresso de escrita em @zgordon no Twitter. Você também pode ouvir Zac falar sobre React no podcast OSTraining.
Neste trecho do livro, Zac oferece uma visão geral de alto nível do React e alguns conceitos-chave.
O que é Reagir?
Fora da caixa, o React é uma biblioteca para construir interfaces de usuário.
Embora o React seja uma biblioteca JavaScript, as interfaces que o React constrói são agnósticas.
Existem várias bibliotecas complementares do React para fazer com que as interfaces que você cria funcionem no navegador, no servidor, em aplicativos nativos e até mesmo em ambientes 360 e VR. Neste livro, nos concentramos em trabalhar com o ReactDOM, a biblioteca que gerencia a adição das interfaces que construímos com o React a sites e aplicativos do lado do cliente. ReactDomServer, ReactNative e React360 também são bibliotecas que você pode explorar para usar interfaces React em outros ambientes.
Além de fornecer funções auxiliares para construir interfaces, a arquitetura do React permite que você lide com interações com suas interfaces, seja envolvendo manipulação de eventos, chamadas de API, gerenciamento de estado, atualizações na interface ou interações mais complexas.
O React não fornece tantas funções auxiliares quanto alguns frameworks JavaScript. É em grande parte por isso que chamamos o React de biblioteca e não de framework. Você ainda precisará escrever bastante JavaScript vanilla ao trabalhar com React.
Arquitetura de componentes do React explicada
Um componente é um pedaço de código independente e reutilizável (criado por meio de uma função ou classe).
O React usa uma arquitetura de componentes para construir interfaces de usuário e organizar o código. O arquivo principal de um aplicativo React simples pode ser algo assim.
// Importar React e outros componentes importe React de 'react'; import { render } de 'react-dom'; importe o cabeçalho de './Header'; importar MainContent de './MainContent'; importar Rodapé de './Rodapé'; função App(){ Retorna ( <div className="app"> <Cabeçalho /> <Conteúdo Principal /> <Rodapé /> </div> ); } ReactDOM.render( <App />, document.getElementById("root"));
Podemos ver aqui alguns componentes em uso. <Header />, <MainContent /> e <Footer /> são todos componentes. A função App() também é um componente e podemos ver na última linha deste exemplo como podemos usar a biblioteca ReactDOM e o método ReactDOM.render() para gerenciar a adição da UI que construímos em uma página da web.
Se cavarmos dentro dos componentes <Header />, <MainContent /> e <Footer />, provavelmente veremos o uso de mais componentes, bem como o que parece ser marcação HTML.
importe Reagir de "reagir"; importar anúncio de "../Ad"; importar logotipo de "../assets/logo.svg"; exportar função padrão Header() { Retorna ( <header className="app-header"> <Anúncio /> <img src={logo} className="app-logo" alt="logo" /> <h1 className="app-title">Nome do site</h1> </header> ); }
Neste componente <Header /> acima, podemos ver que estamos puxando outro componente chamado <Ad />. A maioria dos aplicativos React contém várias camadas de aninhamento de componentes, como vemos com <App />, <Header /> e <Ad />.
Também vemos o uso de elementos HTML em nosso código React. Isso é possível graças a uma biblioteca chamada JSX, que permite escrever “marcação HTML” diretamente em seu JavaScript. Como estamos usando React para criar interfaces de usuário, e interfaces de usuário na web envolvem marcação HTML, faz sentido vermos elementos semelhantes a HTML em nossos componentes de interface do usuário. Exploraremos o JSX em profundidade neste livro.
Se olharmos para algum código de um aplicativo React simples construído usando o React 360, a biblioteca VR do React, os componentes reais que chamamos seriam diferentes, mas a arquitetura do componente ainda está presente.
importe React de 'react'; importar { Texto, Visualizar, VrButton, } de 'react-360'; class Slideshow estende React.Component { // Código removido por brevidade Retorna ( <Visualizar style={styles.wrapper}> <Visualizar style={styles.controls}> <VrButton onClick={this.prevPhoto}> <Text>{'Anterior'}</Text> </VrButton> <VrButton onClick={this.nextPhoto}> <Text>{'Próximo'}</Text> </VrButton> <Visualizar> <Text style={styles.title}>{current.title}</Text> </Visualizar> </Visualizar> ); }
O código acima cria várias camadas de visualizações 360 com alguns botões e texto sobrepostos. Embora o código real possa não fazer todo o sentido, deve ficar claro que temos vários componentes aninhados representando visualização, botões e texto.
Este é um bom exemplo porque você pode ver como os mesmos componentes são reutilizados de maneiras diferentes, passando a eles parâmetros diferentes, ou o que o React chama de props. Entender como os dados passam pelos componentes do React é importante para entender a arquitetura de componentes típica usada para construir com o React.
Fluxo de dados do React explicado
O React segue uma convenção de obter e definir dados no ponto mais alto necessário em uma hierarquia de componentes para que os dados passem em uma direção para baixo através de um aplicativo. Vamos dar uma olhada neste exemplo e imaginar alguns dos tipos de dados que precisaríamos para vários componentes.
função App() { Retorna( <React.Fragment> <Cabeçalho /> <Conteúdo /> <Barra Lateral /> <Rodapé /> </React.Fragment> ); }
Algo como o nome do site pode precisar estar disponível para <Header /> e <Footer />. O conteúdo principal para a página específica precisaria ser passado para <Content />. Alguns dados adicionais do widget podem precisar ir para <Sidebar />.
função App() { const título do site = getTítulo do site(); const widgets = getWidgets(); const mainContent = getPageContent(); Retorna( <React.Fragment> <Header siteTitle={siteTitle} /> <Conteúdo mainContent={mainContent} /> <Widgets da barra lateral={widgets} /> <Rodapé siteTitle={siteTitle} /> </React.Fragment> ); }
Essa convenção de criar nomes de atributos e atribuir-lhes um valor é como passamos dados para um componente.
Agora o <Header /> e o <Footer /> têm acesso ao siteTitle, o <Content /> tem acesso ao mainContent e o <Sidebar /> tem acesso aos widgets de que precisa.
Uma observação importante é que esse padrão de passar dados para um componente apenas passa os dados em um nível. Componentes dentro de <Header /> não terão acesso automaticamente ao siteTitle.

função Cabeçalho(props) { Retorna( <cabeçalho> <p>Podemos ver o {props.siteTitle} aqui.</p> <PageHeader siteTitle={props.siteTitle} /> <PageSubHeader /> </header> ); }
Você pode ver aqui que dentro de <Header /> podemos chamar props.siteTitle e ter acesso ao valor que passamos para ele. No entanto, se quiséssemos ter acesso ao siteTitle dentro do componente <PageHeader />, teríamos que passar manualmente essas informações também.
Quando um componente recebe um valor como prop, ele não deve modificá-lo. Props devem passar por uma árvore de componentes como dados imutáveis. Isso garante que qualquer componente que faça referência a uma prop, faça referência ao mesmo valor que o pai dos componentes filhos.
O valor de uma prop só deve ser alterado no componente que originalmente definiu o valor da prop e começou a passá-lo pela árvore de componentes. Em nosso código de exemplo acima, o componente <App /> pode alterar o valor de siteTitle, mas os componentes <Header /> ou <PageHeader /> não devem.
Para entender o fluxo de como os dados dinâmicos são atualizados em um aplicativo React, é necessário discutir o estado e como os manipuladores de eventos podem ser passados como props.
Estados do componente React explicados
Como aprendemos, os dados fluem inalterados através de componentes como adereços. Os dados são definidos no componente mais alto da árvore necessário para que todos os componentes filhos recebam as informações necessárias como adereços.
Em alguns casos, esses dados são recebidos uma vez e não precisam ser alterados. Em muitos casos, porém, esses dados devem permanecer dinâmicos e ter a capacidade de atualizar a qualquer momento e ter essa atualização refletida em todos os componentes filhos.
Para acompanhar os dados que mudam no React, temos um objeto de estado React e um conjunto de funções auxiliares para atualizar o valor do estado.
Aqui está um exemplo de um contador que se atualizaria. O valor do contador é um valor dinâmico dentro desse componente e, portanto, é um bom exemplo de quando confiar no estado. Observe que para fazer componentes com estado, devemos usar classes JavaScript em vez de funções.
class Counter estende Componente { estado = { contador:0 }; handleCount = () => { this.setState({ contador: this.state.counter + 1 }); }; render(){ Retorna ( <div> <h1>{this.state.counter}</h1> <button onClick={this.handleCount}>Contagem progressiva!!</button> </div> ); } }
Agora é importante observar que esse estado tem como escopo apenas esse componente. O valor de state em counter não estaria disponível para componentes filho ou pai.
Então, em um exemplo de exemplo mais complexo, como abaixo, teríamos que passar o valor de counter down como um prop para o elemento filho.
class Counter estende Componente { estado = { contagem: 0 }; handleCount = () => { this.setState({ contagem: this.state.count + 1 }); }; render(){ Retorna ( <div> <PageHeader count={this.state.count} /> <button onClick={this.handleCount}>Contagem progressiva!!</button> </div> ); } }
A prop <PageHeader /> count é atualizada toda vez que atualizamos o estado no componente <Counter />
function Cabeçalho da página(props) { return <h1>{props.count}</h1>; }
O bom dessa abordagem é que sempre que o estado for atualizado, um novo valor será automaticamente passado para qualquer componente filho com o valor de um prop definido como estado.
Isso nos permite ter um único ponto de verdade para dados dinâmicos. A fonte da verdade é o valor em estado, gerido a partir de um único componente. Todas as instâncias desse valor em componentes filhos são valores imutáveis recebidos como props que não devem ser alterados fora desse componente.
Os componentes que aparecem acima desse componente na hierarquia não teriam acesso a esses dados, pois eles são transmitidos apenas por meio de props. Vemos novamente por que tentamos definir e gerenciar o estado de componentes mais altos na hierarquia para que os dados estejam disponíveis para tudo o que precisar.
Existem alguns outros padrões de arquitetura, como componentes de ordem superior e a API de contexto, que evitam a necessidade de passar manualmente toneladas de adereços pelo seu aplicativo. Vamos explorá-los com mais profundidade mais tarde. Por enquanto, queremos ter certeza de que entendemos essa visão geral de alto nível de como as coisas geralmente funcionam antes de começarmos a usar atalhos.
Atualizando Estados de Componentes no React
Agora, o que acontece quando queremos acionar o estado para ser atualizado de um componente filho?
Imagine, por exemplo, que com o exemplo acima queríamos ter um componente <Button /> em vez de um botão codificado em nosso componente principal <Counter />? Na verdade, isso é bastante comum em aplicativos complexos.
A solução para isso, no mundo React, é passar a função do manipulador de eventos que atualiza o estado com setState down como prop. Em seguida, ele pode ser chamado de qualquer componente filho, mas a ação ocorrerá no componente original que definiu o estado e também tem a capacidade de atualizá-lo. Existem outros padrões para isso, mas essa abordagem é a mais básica.
Se você não estiver familiarizado com a passagem de funções como parâmetros, é um JavaScript vanilla completamente válido.
Depois que o estado for atualizado, ele será transmitido pela hierarquia de componentes por meio dos adereços.
Aqui está um exemplo de como seria.
class Counter estende Componente { estado = { contagem: 0 }; handleCount = () => { this.setState({ contagem: this.state.count + 1 }); }; render(){ Retorna ( <div> <PageHeader count={this.state.count} /> <Button handleCount={this.handleCount} /> </div> ); } } function PageHeader(props) { Retorna( <h1>{props.count}</h1> ); } função Botão(props) { Retorna( <button onClick={props.handleCount}>Contagem progressiva!!</button> ); }
Aqui podemos ver um exemplo simples de como o React lida com o fluxo de dados. Há um único ponto de verdade para os dados. Que existe em estado definido e atualizado a partir de um único componente. Os dados são passados em um fluxo de sentido único através de uma árvore de componentes aninhada por meio de props.
Se o estado precisar ser atualizado de um componente diferente de onde foi definido originalmente, um manipulador de eventos poderá ser passado para o componente filho necessário como um prop. Isso mantém os dados imutáveis e fluindo de uma maneira porque, mesmo que um componente filho acione uma alteração, essa alteração ocorre mais acima no componente original.
Quando atribuímos o valor de uma prop a algo do estado, como abaixo, esse valor da prop será atualizado automaticamente sempre que o estado mudar.
<PageHeader counter={this.state.count} />
Qualquer outro componente filho que faça referência a esse valor prop também receberá a atualização automaticamente. Essa é a beleza do fluxo de dados no React.
Isso pode demorar um pouco para se acostumar, dependendo de como você abordou problemas como esses com JavaScript no passado. No entanto, tudo isso deve servir como um bom ponto de partida para podermos aprofundar a explicação do React.