Neste tutorial, aprenderemos como construir um aplicativo de plataforma cruzada que roda em iOS, Android e na web usando Expo .

Reaja nativo vs. Expo: Qual é a diferença?

Antes de começarmos a usar o Expo, quero abordar como ele é semelhante e diferente do React Native.

Resumindo, Expo vive como um superconjunto do React Native. Tudo o que o React Native faz a Expo pode fazer, mas o React Native não pode fazer tudo o que a Expo pode (por padrão).

O React Native oferece todas as ferramentas e opções, enquanto o Expo toma algumas decisões por você. Essas decisões são baseadas no que é comumente necessário em aplicativos React Native e, portanto, tira muito do trabalho tedioso e das decisões da equação.

Além disso, por ser uma plataforma padronizada para ser construída, ela permite que você aproveite uma série de ferramentas e serviços incríveis, como o Expo Snack, que permite criar aplicativos nativos no navegador .

Agora, com isso resolvido, vamos construir um aplicativo multiplataforma com o Expo.

Instalando Expo

Expo tem algumas das melhor documentação que já possuí descobri, mas vou dar um rápido resumo de como instalá-lo.

Curiosamente, apesar da Expo ser um superconjunto do React Native, não precisamos instalar o React Native em nosso sistema para construir um aplicativo Expo. Vamos aproveitar a infraestrutura deles para fazer o trabalho pesado nos bastidores.

A Expo tem três requisitos:

  1. Node.js (vá com a versão LTS)
  2. Git
  3. Watchman (Watchman observa os arquivos para atualizar automaticamente o aplicativo)

Com aqueles em seu sistema, você pode instalar o Expo CLI globalmente via NPM.

 npm install--global expo-cli

Verifique a instalação executando expo whoami . Você verá que não está conectado.

Como aproveitaremos a infraestrutura da Expo, precisamos criar uma conta. Você pode fazer isso por meio do expo register ou fazendo login em sua conta existente com expo login .

Antes de começar a construir, vamos descobrir como vamos executar nosso aplicativo. Temos três plataformas nas quais trabalharemos: iOS, Android e a web.

A web é fácil. Para iOS e Android, sugiro baixar o aplicativo Expo Go na app store. Isso permitirá que você acesse seus aplicativos Expo em seu dispositivo sem ter que passar pelo processo de publicação. Não se preocupe, você poderá publicar seu aplicativo com sua própria marca mais tarde-isso torna o desenvolvimento muito rápido.

Criação de um aplicativo multiplataforma

Criar um novo aplicativo Expo é tão fácil quanto executar a seguinte linha de comando:

 expo init MyCrossPlatformApp

Ao executar isso, você deverá escolher um modelo.

Uma observação importante sobre fluxos de trabalho gerenciados versus simples: “Gerenciado” significa que você está aproveitando a infraestrutura da Expo. “Bare” significa que você está usando o modelo, desconectando-se do serviço e gerenciando tudo por conta própria. Você sempre pode exportar de um fluxo de trabalho gerenciado para um vazio, mas não pode voltar atrás. Eu sempre sugeriria começar com um fluxo de trabalho gerenciado.

Vou escolher o modelo “tabs (TypeScript)” para termos o maior retorno do nosso investimento (ou seja, navegação configurada).

TypeScript Tab

E aí está! Um aplicativo de plataforma cruzada que será executado em iOS, Android e na web. Execute yarn start e ele imprimirá um código QR que você pode escanear da câmera em seu dispositivo iOS ou Android para abrir o aplicativo Expo Go, executá-lo e obter atualizações em tempo real a cada arquivo salvo.

Como alternativa, você pode executar o yarn web e ele abrirá o navegador.

Se você tiver o simulador iOS ou o emulador Android instalado em sua máquina, poderá executá-los e ele abrirá o respectivo simulador ou emulador, mas não é necessário.

Navegando no projeto Expo

O template Expo que escolhemos é um bom suporte para você. Há uma variedade de arquivos e pastas em que você terá interesse:

  • App.tsx -Este é o ponto de entrada de nosso arquivo. É um bom lugar para fazer qualquer trabalho de configuração necessário para seu aplicativo
  • telas/-Este diretório contém as telas que registramos em nosso navegador
  • navegação/-Este diretório gerencia tudo relacionado à navegação. Ele pode se tornar muito extenso por causa de todas as plataformas que temos como alvo, mas o React Navigation, incluído neste modelo de Expo, simplifica muito as coisas
  • ganchos/-os ganchos são uma forma comum de gerenciar a funcionalidade em aplicativos React/React Native. Este diretório compila ganchos personalizados do aplicativo
  • constantes/-Este diretório é usado para manter valores estáticos que não mudam
  • componentes/-Este diretório é onde você deseja armazenar os componentes reutilizáveis ​​que constituem a funcionalidade de seu aplicativo. Eles são usados ​​por telas ou até mesmo outros componentes

Escrever código e criar uma lista de tarefas na Expo

Vamos pular para alguns códigos e criar uma lista de tarefas simples. Estaremos trabalhando em screens/TabOneScreen.tsx . Vá em frente e exclua tudo desse arquivo.

Primeiro, temos nossas importações. Eles são o que usaremos para construir nossa IU e, em seguida, adicionar funcionalidade.

 import * as React from"react";
import {StyleSheet, TextInput, ScrollView, View, Text} de"react-native";

Observe que as importações react-native realmente mapeiam para a visualização nativa subjacente da plataforma em que o aplicativo está sendo executado. Por exemplo, uma View torna-se:

  • iOS → UIView
  • Android → ViewGroup
  • Web → div

A seguir, vamos criar uma lista de tarefas.

//... função padrão de exportação TabOneScreen () { tarefas const=[ {título:"Excluir tudo", completo: verdadeiro}, {title:"Faça uma lista de tarefas de trabalho", complete: false}, ]; Retorna (   {tasks.map ((tarefa, índice)=> { const textStyles=[styles.taskText]; if (task.complete) { textStyles.push (styles.taskTextComplete); } Retorna (  {task.title}  ); })}   );
} estilos const=StyleSheet.create ({ container: { flex: 1, backgroundColor:"#fff", }, contentContainer: { marginVertical: 10, marginHorizontal: 20, }, tasksContainer: { marginTop: 15, }, taskText: { fontSize: 18, marginVertical: 3, }, taskTextComplete: { textDecorationLine:"line-through", fontSize: 18, marginVertical: 3, },
});

Tab One Title

Temos uma série de tarefas que rastreiam um título e um status completo, que iteramos por meio do map e os renderizamos na tela.

O que é único no Expo/React Native em comparação com a web é que precisamos declarar explicitamente que essa visualização deve ser rolável. É para isso que serve o ScrollView .

Finalmente, usamos StyleSheet para definir alguns estilos para nossa tela. Eles são mapeados para propriedades CSS típicas, mas no formato CSS-in-JS.

Agora vamos capturar a entrada do usuário. Usaremos os estados TextInput e React para fazer isso.

 exportar função padrão TabOneScreen () { tarefas const=[ {título:"Excluir tudo", completo: verdadeiro}, {title:"Faça uma lista de tarefas de trabalho", complete: false}, ]; const [inputValue, setInputValue]=React.useState (""); Retorna (   setInputValue (texto)} placeholder="Próxima tarefa" onSubmitEditing={()=> { setInputValue (""); }} />  {tasks.map ((tarefa, índice)=> { const textStyles=[styles.taskText]; if (task.complete) { textStyles.push (styles.taskTextComplete); } Retorna (  {task.title}  ); })}   );
} estilos const=StyleSheet.create ({ //... entrada: { backgroundColor:"# f3f3f3", paddingHorizontal: 10, paddingVertical: 5, borderRadius: 5, largura:"80%", fontSize: 20, borderWidth: 1, borderColor:"# dad4d4", },
});

Tab One Title 2

Semelhante a como um View mapeia para os componentes nativos subjacentes em cada plataforma, um TextInput faz o mesmo. Nós o configuramos para capturar o valor que o usuário digitou e armazená-lo no estado por meio de React.useState . Assim que o botão enter/done é pressionado, o valor é redefinido.

React.useState é como você deseja gerenciar dados que mudam dinamicamente para que, à medida que mudam, a IU seja atualizada.

Atualmente, quando enviamos a entrada, ele apenas redefine o valor da entrada. Vamos realmente armazenar e exibir suas entradas.

//... const useTasks=()=> { const [tarefas, setTasks]=React.useState ([ {título:"Excluir tudo", completo: verdadeiro}, {title:"Faça uma lista de tarefas de trabalho", complete: false}, ]); const addTask=(title: string)=> { setTasks ((existingTasks)=> [... existingTasks, {title, complete: false}]); }; Retorna { tarefas, addTask, };
}; função padrão de exportação TabOneScreen () { const {tarefas, addTask}=useTasks (); const [inputValue, setInputValue]=React.useState (""); Retorna (   setInputValue (texto)} placeholder="Próxima tarefa" onSubmitEditing={()=> { addTask (inputValue); setInputValue (""); }} /> {/*... */}  );
} //...

Aqui, criamos um gancho personalizado chamado useTasks . Nele, rastreamos nosso array de tarefas usando React.useState porque ele mudará dinamicamente, portanto, precisaremos renderizar novamente nossa tela quando os dados mudarem.

Também criamos uma função addTask que anexa a tarefa, devidamente formatada, à nossa lista de tarefas.

Agora, ao adicionar addTask (inputValue) , o texto que um usuário digita e envia no prop onSubmitEditing será adicionado à matriz de tarefas e automaticamente atualizado na tela.

Finalmente, vamos permitir que um usuário alterne se uma tarefa foi concluída ou não.

//... const useTasks=()=> { const [tarefas, setTasks]=React.useState ([ {título:"Excluir tudo", completo: verdadeiro}, {title:"Faça uma lista de tarefas de trabalho", complete: false}, ]); const addTask=(title: string)=> { setTasks ((existingTasks)=> [... existingTasks, {title, complete: false}]); }; const toggleTaskStatus=(índice: número)=> { setTasks ((existingTasks)=> { alvo const=tarefas existentes [índice]; Retorna [ ... existingTasks.slice (0, índice), { ...alvo, complete:! target.complete, }, ... existingTasks.slice (índice + 1), ]; }); }; Retorna { tarefas, addTask, toggleTaskStatus, };
}; função padrão de exportação TabOneScreen () { const {tarefas, addTask, toggleTaskStatus}=useTasks (); const [inputValue, setInputValue]=React.useState (""); Retorna (  {/*... */}  {tasks.map ((tarefa, índice)=> { const textStyles=[styles.taskText]; if (task.complete) { textStyles.push (styles.taskTextComplete); } Retorna (  toggleTaskStatus (índice)}> {task.title}  ); })}   );
} //...

Dentro do gancho useTasks personalizado, criamos uma função toggleTaskStatus que encontrará a tarefa no índice fornecido e alternará seu status completo, alterando assim o estilo.

Novamente, como estamos usando React.useState , a IU será renderizada novamente com dados atualizados assim que chamarmos a função.

Aqui está nosso código finalizado para este arquivo:

//telas/TabOneScreen.tsx import * as React from"react";
import {StyleSheet, TextInput, ScrollView, View, Text} de"react-native"; const useTasks=()=> { const [tarefas, setTasks]=React.useState ([ {título:"Excluir tudo", completo: verdadeiro}, {title:"Faça uma lista de tarefas de trabalho", complete: false}, ]); const addTask=(title: string)=> { setTasks ((existingTasks)=> [... existingTasks, {title, complete: false}]); }; const toggleTaskStatus=(índice: número)=> { setTasks ((existingTasks)=> { alvo const=tarefas existentes [índice]; Retorna [ ... existingTasks.slice (0, índice), { ...alvo, complete:! target.complete, }, ... existingTasks.slice (índice + 1), ]; }); }; Retorna { tarefas, addTask, toggleTaskStatus, };
}; função padrão de exportação TabOneScreen () { const {tarefas, addTask, toggleTaskStatus}=useTasks (); const [inputValue, setInputValue]=React.useState (""); Retorna (   setInputValue (texto)} placeholder="Próxima tarefa" onSubmitEditing={()=> { addTask (inputValue); setInputValue (""); }} />  {tasks.map ((tarefa, índice)=> { const textStyles=[styles.taskText]; if (task.complete) { textStyles.push (styles.taskTextComplete); } Retorna (  toggleTaskStatus (índice)}> {task.title}  ); })}   );
} estilos const=StyleSheet.create ({ container: { flex: 1, backgroundColor:"#fff", }, contentContainer: { marginVertical: 10, marginHorizontal: 20, }, tasksContainer: { marginTop: 15, }, taskText: { fontSize: 18, marginVertical: 3, }, taskTextComplete: { textDecorationLine:"line-through", fontSize: 18, marginVertical: 3, }, entrada: { backgroundColor:"# f3f3f3", paddingHorizontal: 10, paddingVertical: 5, borderRadius: 5, largura:"80%", fontSize: 20, borderWidth: 1, borderColor:"# dad4d4", },
});

Usando o código do NPM

Uma das melhores partes do React Native é que podemos explorar o extenso ecossistema NPM para usar código de terceiros em nosso aplicativo. Vamos migrar nosso TextInput para usar componentes estilizados .

Primeiro, vamos instalar o pacote.

 yarn adicionar componentes estilizados

Então, podemos substituir nosso TextInput por uma versão de componentes estilizados .

 import * as React from"react";
import {StyleSheet, ScrollView, View, Text} de"react-native";
importar estilizado de"componentes com estilo/nativo"; const Input=styled.TextInput` cor de fundo: # f3f3f3; raio da borda: 5; preenchimento esquerdo: 10; padding-right: 10; acolchoamento superior: 5; acolchoamento inferior: 5; largura: 80%; tamanho da fonte: 20; largura da borda: 1; border-color: # dad4d4;
`; //... função padrão de exportação TabOneScreen () { const {tarefas, addTask, toggleTaskStatus}=useTasks (); const [inputValue, setInputValue]=React.useState (""); Retorna (   setInputValue (texto)} placeholder="Próxima tarefa" onSubmitEditing={()=> { addTask (inputValue); setInputValue (""); }} /> {/*... */}  );
} //...

O que é ótimo aqui é que, assim como usar os componentes principais do React Native, Componentes de estilo seguirá em frente e traduzirá nossos componentes no componente nativo relevante para a plataforma em que o aplicativo está sendo executado. Também podemos usar CSS tradicional aqui.

O código completo usando styled-components :

 import * as React from"react";
import {StyleSheet, ScrollView, View, Text} de"react-native";
importar estilizado de"componentes com estilo/nativo"; const Input=styled.TextInput` cor de fundo: # f3f3f3; raio da borda: 5; preenchimento esquerdo: 10; padding-right: 10; acolchoamento superior: 5; acolchoamento inferior: 5; largura: 80%; tamanho da fonte: 20; largura da borda: 1; border-color: # dad4d4;
`; const useTasks=()=> { const [tarefas, setTasks]=React.useState ([ {título:"Excluir tudo", completo: verdadeiro}, {title:"Faça uma lista de tarefas de trabalho", complete: false}, ]); const addTask=(title: string)=> { setTasks ((existingTasks)=> [... existingTasks, {title, complete: false}]); }; const toggleTaskStatus=(índice: número)=> { setTasks ((existingTasks)=> { alvo const=tarefas existentes [índice]; Retorna [ ... existingTasks.slice (0, índice), { ...alvo, complete:! target.complete, }, ... existingTasks.slice (índice + 1), ]; }); }; Retorna { tarefas, addTask, toggleTaskStatus, };
}; função padrão de exportação TabOneScreen () { const {tarefas, addTask, toggleTaskStatus}=useTasks (); const [inputValue, setInputValue]=React.useState (""); Retorna (   setInputValue (texto)} placeholder="Próxima tarefa" onSubmitEditing={()=> { addTask (inputValue); setInputValue (""); }} />  {tasks.map ((tarefa, índice)=> { const textStyles=[styles.taskText]; if (task.complete) { textStyles.push (styles.taskTextComplete); } Retorna (  toggleTaskStatus (índice)}> {task.title}  ); })}   );
} estilos const=StyleSheet.create ({ container: { flex: 1, backgroundColor:"#fff", }, contentContainer: { marginVertical: 10, marginHorizontal: 20, }, tasksContainer: { marginTop: 15, }, taskText: { fontSize: 18, marginVertical: 3, }, taskTextComplete: { textDecorationLine:"line-through", fontSize: 18, marginVertical: 3, },
});

E isso é tudo, pessoal, para construir um aplicativo multiplataforma que roda em iOS, Android e na web usando o Expo! É um fluxo de trabalho, uma empresa e uma equipe fantásticos que permitirão que você multiplique seu impacto no desenvolvimento enquanto cria experiências verdadeiramente nativas.

A postagem Criação de aplicativos multiplataforma com Expo em vez de React Native apareceu primeiro no LogRocket Blog .

Source link