Aplicativo gerador de tokens
⚙️ Configuração inicial
Vamos criar o projeto do nosso aplicativo usando o prompt de comando ou o Terminal do VSCODE
Crie um repositório vinculado ao Github (Eu criei uma pasta no C: chamada app)

Dentro do terminal do VSCode ou pelo prompt de comando, vamos criar o projeto usando a plataforma expo, mas antes podemos atualizar o node package manager Veja imagens e copie o código.
npm install -g npm@latest


npx create-expo-app geradorToken
Após a criação do projeto Expo, é interessante fazer um commit no Github para versionar essa etapa.
Abrir o Android Studio e abrir o emulador de smartphone Android.
De volta ao CMD ou ao VSCode, vamos iniciar o servidor Expo para disponibilizar o projeto através do IP da nossa conexão. Repare que devemos estar dentro da pasta do projeto Expo.

Antes de iniciar o expo, podemos adicionar uma atualização que permitirá emular o app na web também:
npx expo install react-native-web react-dom @expo/metro-runtime
Vou deixar aqui também a sintaxe que atualiza o expo caso necessário:
npx expo install expo@latest
E por fim, vamos iniciar o projeto expo com o seguinte código:
npx expo start

A tela acima deverá surgir e então os seguintes caminhos poderão ser seguidos
pressionar a tecla “a” irá instalar e abrir o app Expo GO no smartphone virtualizado. pressionar a tecla “w” irá abrir no localhost no seu navegador.
Scannear o QRCode com o app do Expo GO instalado no seu Smartphone. Obs. Seu Smartphone e seu computador deverão estar na mesma rede.
Caso ocorra algum erro, utilize o atalho Ctrl+C para interromper o servidor do expo e tente reiniciar usando o código anterior. Ao terminar o procedimento, sua tela deverá estar parecida com a imagem abaixo.

Possíveis problemas:
Problema associado ao ANDROID_HOME: reiniciar o computador ou refazer a variável de ambiente para sua conta.
npx expo start não inicia: executar a atualização do npm conforme abaixo:
npm install -g npm@latest
Problema Metro waiting on 127.0.0.1: nesse caso você pode tentar usar o tunnel para hospedar provisoriamente na web:
npx expo start --tunnel
#no primeiro acesso irá solicitar a instalação de uma dependência
Surgirá algo como esse exemplo:

📱Front-end
Vamos iniciar nossa diagramação entendendo alguns conceitos
Vamos editar o arquivo App.js com o seguinte código:
export default function App() {
return(
)
};
Todo projeto react-native é um componente exportado. Vamos agora criar áreas de visualização:
export default function App() {
return(
<View>
</View>
)
}
Seria como se fosse uma <div> no html. Porém precisamos importar todos os componentes usados na função, logo precisamos inserir um código acima:
import { View } from "react-native";
Se eu quiser criar um texto dentro da view, vou usar a tag Text:
<Text>
Meu app!
</Text>
Como dito anteriormente, se vou inserir uma nova tag, precisamos importar o recurso:
import { View, Text } from "react-native";
Para poder estilizar esse conteúdo, vamos criar uma constante que receberá a função create do método StyleSheet, que também deverá ser importado:
const estilos=StyleSheet.create({
})
Com a importação, o código completo deverá estar assim:
import { View, Text, StyleSheet } from "react-native";
export default function App() {
return (
<View>
<Text>
Meu app!
</Text>
</View>
)
}
const estilos=StyleSheet.create({
})
Nesse momento, podemos estilizar qualquer item criado referenciando a constante declarada. Por exemplo:
<View style={estilos.container}>
Como definimos o container pertencendo ao estilos, então deveremos considera-lo na estilização:
const estilos=StyleSheet.create({
container:{
}
})
E assim podemos inserir elementos que estilizam nosso conteúdo e no final teremos essa concepção de código:
const estilos= StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f3f3ff",
justifyContent: 'center',
alignItems: 'center'
}
})
Para inserir uma imagem, vamos fazer download da figura png abaixo e salva-la dentro da pasta assets


Em seguida, vamos inserir o seguinte código dentro da View:
<Image source={require("./assets/logo.png")} style={estilos.logo}/>
Naturalmente, se estamos usando uma nova tag, precisamos importa-la também:
import { View, Text, StyleSheet, Image } from "react-native";
Vamos inserir o estilo do logo também em nossa tabela de estilos:
const estilos= StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f3f3ff",
justifyContent: 'center',
alignItems: 'center'
},
logo: {
marginBottom: 60
}
})
Repare que é necessário separar as referências por vírgula.
Bom, agora podemos criar outra tela e aprender a fazer o roteamento.
Vamos criar uma nova pasta na nossa estrutura e vamos criar dois arquivos.

O index.js acabará sendo nossa página principal e o arquivo paginasenhas.js representará nossa segunda página.
Vamos trabalhar um pouco na nossa páginasenhas.js com o seguinte código:
// paginaSenhas.js
export function PaginaSenhas() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View>
<Text>
Minhas senhas
</Text>
</View>
</SafeAreaView>
)
}
const estilos= StyleSheet.create({
})
Repare que uma nova tag surgiu, a SafeAreaView, que inclusive está recebendo uma estilização em linha.
Então deveremos resolver os imports:
import { View, StyleSheet, Text} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
Agora inserindo os estilos, ficamos com o código assim:
import { View, StyleSheet, Text} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export function PaginaSenhas() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={estilos.header}>
<Text style={estilos.title}>
Minhas senhas
</Text>
</View>
</SafeAreaView>
)
}
const estilos = StyleSheet.create({
header: {
padding: 14,
paddingTop: 58,
backgroundColor: "#392de9"
},
title: {
fontSize: 18,
fontWeight: "bold",
color: "#FFF"
}
})
Como o Expo somente reproduz aquilo que está no App.js exportado como default function, então não é possível ver como está ficando essa tela antes de fazer o roteamento.
Para podermos acompanhar as mudanças pelo servidor Expo no Android, vamos acertar as páginas index.js e App.js
Precisaremos copiar todo conteúdo do arquivo App.js para index.js alterando a linha export default function App() conforme abaixo:
export function Home() {
Para entender melhor o sistema de roteamento, vamos iniciar acessando o site abaixo:
https://reactnavigation.org/docs/getting-started
Precisaremos pegar o código de instalação da dependência, para assim poder fazer os imports.
npm install @react-navigation/native
npx expo install react-native-safe-area-context
npm install @react-navigation/bottom-tabs
Após instalação, vamos reiniciar o servidor Expo e criar o arquivo routes.js conforme imagem:

No arquivo routes.js, iremos iniciar a base do roteamento com o seguinte código:
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
const Tab = createBottomTabNavigator();
export function Routes() {
return (
<Tab.Navigator>
<Tab.Screen />
<Tab.Screen />
</Tab.Navigator>
)
}
Em seguida, vamos informar o roteamento importando nossos componentes criados, ou seja, nossas páginas.
import { Home } from './pages/index'
import { PaginaSenhas } from './pages/paginaSenhas'
Vamos informar as páginas que cada botão deverá abrir:
<Tab.Screen name="home" component={Home}/>
<Tab.Screen name="paginaSenhas" component={PaginaSenhas}/>
O código do arquivo routes.js ficará assim:
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import {Home} from './Pages/index';
import {PaginaSenhas} from './Pages/paginaSenhas';
const Tab = createBottomTabNavigator();
export function Routes() {
return (
<Tab.Navigator>
<Tab.Screen name="home" component={Home}/>
<Tab.Screen name="paginaSenhas" component={PaginaSenhas}/>
</Tab.Navigator>
)
}
Em seguida, vamos abrir o arquivo App.js, apagar o código e escrever como deve ser feito o direcionamento do Expo para o roteamento:
import { NavigationContainer } from '@react-navigation/native'
import { Routes } from './routes'
export default function App() {
return (
<NavigationContainer>
<Routes />
</NavigationContainer>
)
}
Repare que agora temos duas possibilidades de navegação, porém ainda sem ícones.

Vamos aprimorar a visibilidade do app usando a plataforma ionic:

Para usar os ícones escolhidos, vamos importar dentro do arquivo routes.js:
import Ionicons from '@expo/vector-icons/Ionicons';
Em seguida, vamos adicionar as opções da Screen:
<Tab.Screen
name="home"
component={Home}
options={{
tabBarShowLabel: false,
headerShown: false,
tabBarIcon: () => {
return(<Ionicons name="home"/>)
}
}}
/>
<Tab.Screen
name="paginaSenhas"
component={PaginaSenhas}
options={{
tabBarShowLabel:false,
headerShown: false,
tabBarIcon: () => {
return (<Ionicons name="lock-closed" />)
}
}}
/>
Os ícones aparecem porém sem estilização. Vamos aplicar algumas mudanças.
tabBarIcon: () => {
return(<Ionicons size={25} color={"#000"} name="home"/>)
O código acima permitirá estilizar o tamanho e a cor do ícone. Agora podemos aplicar um desvio condicional para dar um efeito na troca de telas:
tabBarIcon: ({focused}) => {
if (focused) {
return (<Ionicons size={25} color={"#000"} name="home" />)
}
return (<Ionicons size={20} color={"#000"} name="home-outline" />)
}
Em resumo, o código aplicado em ambas navegações ficou dessa forma:
<Tab.Screen
name="home"
component={Home}
options={{
tabBarShowLabel: false,
headerShown: false,
tabBarIcon: ({focused}) => {
if (focused) {
return (<Ionicons size={25} color={"#000"} name="home" />)
}
return (<Ionicons size={20} color={"#000"} name="home-outline" />)
}
}}
/>
<Tab.Screen
name="paginaSenhas"
component={PaginaSenhas}
options={{
tabBarShowLabel: false,
headerShown: false,
tabBarIcon: ({focused}) => {
if (focused) {
return (<Ionicons size={25} color={"#000"} name="lock-closed" />)
}
return (<Ionicons size={20} color={"#000"} name="lock-closed-outline" />)
}
}}
/>
Agora que o roteamento está funcionando com os ícones estabelecidos, vamos finalizar nossa tela principal, então vamos abrir o arquivo index.js.
Para adicionar o Slider, precisamos instalar uma nova dependência que se encontra nesse link:
https://docs.expo.dev/versions/latest/sdk/slider
npx expo install @react-native-community/slider
Após a instalação, vamos inserir uma nova View com o Slider interno logo após a tag Text, em nosso arquivo index.js:
<View>
<Slider/>
</View>
Como estamos usando uma nova tag, devemos importar seu componente também:
import Slider from "@react-native-community/slider";
Vamos então inserir uma customização ao slider, estilizando a View:
style={estilos.area}
Posteriormente, vamos adicionar os padrões de estilo. Não se esqueça de separar os elementos por vírgula.
area: {
marginBottom: 14,
marginTop: 14,
width: "80%",
backgroundColor: "#FFF",
borderRadius: 8,
padding: 8
}
Defina uma altura para o Slider:
<Slider style={{ height: 50 }} />
Vamos adicionar mais parâmetros ao Slider para definir os valores limites:
minimumValue={6}
maximumValue={20}
Vamos também trabalhar em algumas cores atribuindo nos parâmetros:
minimumTrackTintColor="#ff0000"
maximumTrackTintColor="#000"
thumbTintColor="#392de9"
Agora vamos entender como funciona botões no react native inserindo o seguinte código após a View:
<TouchableOpacity style={estilos.button}>
<Text style={estilos.buttonText}>
Gerar Senha
</Text>
</TouchableOpacity>
Note que agora temos uma nova tag, e também temos novos estilos, sendo assim vamos continuar acrescentando a tag ao import:
import { View, StyleSheet, Text, Image, TouchableOpacity } from "react-native";
E definindo os estilos:
button: {
backgroundColor: "#392de9",
width: "80%",
height: 50,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 8,
},
buttonText: {
color: "#FFF"
},
Agora podemos definir mais algumas propriedades do nosso slider. Primeiramente vamos entender o conceito do useState:
import { useState } from "react";
O useState
é um Hook (função) em React que permite adicionar funcionalidade de estado em componentes funcionais. Ele retorna um par de valores: o estado atual e uma função que atualiza esse estado. Quando useState
é chamado, aceita o estado inicial como argumento e retorna um array contendo o estado atual e uma função para atualizá-lo.
Vamos definir onde o texto será trocado inserindo o código abaixo no lugar da frase Meu app!:
{qtde} Caracteres
Vamos usar o useState para definir o valor padrão e seu controlador:
const [qtde, defineQtde] = useState(6)
E atribuir o parâmetro dentro do Slider:
value={qtde}
Agora vamos a parte mais importante, informar que a cada mudança no slider queremos que o valor da nossa variável se altere, inserindo o parâmetro a seguir:
onValueChange={(value) => defineQtde(value)}
Para manter apenas os números inteiros, vamos inserir a função toFixed à variável:
onValueChange={(value) => defineQtde(value.toFixed(0))}
Vamos estilizar o texto:
style={estilos.caracteres}
caracteres:{
fontSize:30,
fontWeight:"bold"
}
Agora vamos construir a tela modal, criando uma pasta components em nosso projeto conforme imagem:

Na tela modal.js, vamos inserir a seguinte estrutura:
import { View, StyleSheet} from "react-native";
export function ModalTokens() {
return (
<View style={estilos.container}>
<View style={estilos.content}>
</View>
</View>
)
}
Em seguida podemos estilizar esse conteúdo:
const estilos= StyleSheet.create({
container: {
backgroundColor: "rgba(25,25,25,0.6)",
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
content: {
backgroundColor: "#FFF",
width: "85%",
paddingTop: 25,
paddingBottom: 25,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 8,
}
})
Para poder chamar essa tela modal no index.js, vamos realizar alguns procedimentos.
Primeiro, Vamos inserir o modal após no final do componente index.js usando o código abaixo:
<Modal>
</Modal>
Nosso objetivo é trazer o componente já criado para dentro do modal:
<Modal >
<ModalTokens/>
</Modal>
E adicionar as importações:
import { View, StyleSheet, Text, Image, TouchableOpacity, Modal } from "react-native";
import { ModalTokens } from '../components/modal';
Agora vamos criar o algoritmo que associa o botão Gerar senha a tela modal, adicionando um método useState que vai controlar a visibilidade:
const [telaModal, configTelaModal]=useState(false)
Vamos informar ao Modal que sua visibilidade será determinada pelo valor do useState e aproveitar para adicionar outros parâmetros:
<Modal visible={telaModal} animationType="fade" transparent={true}>
E criar uma função que altera o valor do useState:
function gerarToken() {
configTelaModal(true);
}
Em seguida vamos associar a função ao botão:
<TouchableOpacity style={estilos.button} onPress={gerarToken}>
Note que agora podemos usar o botão para chamar o Modal. Porém não podemos voltar, pois não criamos a estrutura para isso. Vamos trabalhar mais no arquivo modal.js
<View style={estilos.container}>
<View style={estilos.content}>
<Text style={estilos.title}>
Senha Gerada
</Text>
<Pressable style={estilos.innerToken} >
<Text style={estilos.text}>
senha
</Text>
</Pressable>
<View style={estilos.buttonArea}>
<TouchableOpacity style={estilos.button} >
<Text style={estilos.buttonText}>
Voltar
</Text>
</TouchableOpacity>
<TouchableOpacity style={[estilos.button, estilos.buttonSave]} >
<Text style={estilos.buttonSaveText}>
Salvar Senha
</Text>
</TouchableOpacity>
</View>
</View>
</View>
Vamos acertar os imports:
import { Text, View, StyleSheet, TouchableOpacity, Pressable } from "react-native";
E vamos usar o código abaixo para estilizar:
const estilos= StyleSheet.create({
container: {
backgroundColor: "rgba(25,25,25,0.6)",
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
content: {
backgroundColor: "#FFF",
width: "85%",
paddingTop: 25,
paddingBottom: 25,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 8,
},
title: {
fontSize: 20,
fontWeight: "bold",
color: "#000",
marginBottom: 25,
},
innerToken: {
backgroundColor: "#0e0e0e",
width: "85%",
padding: 14,
borderRadius: 8
},
text: {
color: "#FFF",
textAlign: "center"
},
buttonArea: {
flexDirection: "row",
width: "90%",
marginTop: 8,
alignItems: "center",
justifyContent: "space-between"
},
button: {
flex: 1,
alignItems: "center",
marginBottom: 14,
marginTop: 14,
margin:9,
padding: 8,
backgroundColor: "#EEEEEE",
borderRadius: 8,
},
buttonSave: {
backgroundColor: "#392DE9"
},
buttonSaveText: {
color: "#FFF",
fontWeight: "bold"
}
})
Agora temos a chamada do overlay, mas não temos ainda a função voltar estabelecida:
Para fechar a tela modal, vamos passar o parâmetro que controla o modal no index.js
<ModalTokens fechar={()=> configTelaModal(false)} />
Em seguida, vamos associar ao botão Voltar no arquivo modal.js:
<TouchableOpacity style={estilos.button} onPress={fechar}>
E passar essa informação ao export function:
export function ModalTokens({fechar}) {
🔗Back-end
Vamos iniciar o Back-end do projeto criando um algoritmo para gerar os tokens
No arquivo index.js vamos declarar a seguinte variável para receber nossa lista de caracteres.
let caracteres = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
Agora vou aproveitar a função de abrir a tela modal para também gerar o token. A função ficará assim:
function gerarToken() {
let token = ""
for (let i = 0, n = caracteres.length; i < qtde; i++) {
token += caracteres.charAt(Math.floor(Math.random() * n))
}
configTelaModal(true);
}
A variável token receberá um caractere aleatório cada vez que passar pelo looping até que a quantidade definida no slider seja atingida.
Agora vamos usar o useState() para aplicar as senhas geradas:
const [tokenValue, configTokenValue] = useState("")
E vamos adicionar a instrução na função abrirModal para atualizar o useState:
configTokenValue(token);
Conferindo, a função abrirModal ficará assim:
function gerarToken() {
let token = ""
for (let i = 0, n = caracteres.length; i < qtde; i++) {
token += caracteres.charAt(Math.floor(Math.random() * n))
}
configTokenValue(token);
configTelaModal(true);
}
Vamos atribuir ao modal o valor do token, deixando a sintaxe dessa forma:
<ModalTokens token={tokenValue} fechar={() => configTelaModal(false)} />
Agora que já informamos ao index que ele receberá um modal atribuído de uma função de fechar e um valor de token, vamos ao arquivo modal.js para consumir o valor do atributo token.
<Text style={estilos.text}>
{token}
</Text>
E também não podemos esquecer de passar essa informação para o componente modalTokens:
export function ModalTokens({token, fechar}) {
Vamos agora permitir que usuários copiem o token gerado, adicionando um atributo ao texto dos tokens:
selectable={true}
Porém podemos utilizar um recurso mais avançado, que permite copiar para área de transferência.
Para isso vamos instalar um recurso do link abaixo:
https://docs.expo.dev/versions/latest/sdk/clipboard
npx expo install expo-clipboard
Com a dependência instalada, vamos editar o arquivo modal.js.
Primeiro vamos já realizar o import da dependência:
import * as Clipboard from 'expo-clipboard';
Agora vamos inserir a função assíncrona no componente:
async function copiarToken() {
await Clipboard.setStringAsync(token)
alert("Token copiado para área de transferência.")
fechar();
}
A função acima salva o token na área de transferência, gera um alert e depois fecha o modal.
Para finalizar, vamos instruir a área Pressable a chamada da função:
<Pressable style={estilos.innerToken} onLongPress={copiarToken} >
Para que tudo funcione corretamente, vamos alterar o atributo anterior do texto:
selectable={false}
Feito isso, precisamos salvar as senhas. Vamos criar um Hook para determinar as regras de uso de armazenamento no app.
Primeiramente, vamos acessar a documentação expo:
https://docs.expo.dev/versions/latest/sdk/async-storage
Nele é possível encontrar a sintaxe de instalação:
npx expo install @react-native-async-storage/async-storage
Após a instalação, vamos montar a pasta hooks com o arquivo bancoTokens.js

No arquivo bancoTokens.js, iremos iniciar importando a dependência:
import AsyncStorage from '@react-native-async-storage/async-storage';
Em seguida, vamos definir a estrutura padrão do componente:
export default function Armazenamento(){
return{
}
}
A função Armazenamento terá 3 tarefas e o código ficará assim:
import AsyncStorage from '@react-native-async-storage/async-storage'
export default function Armazenamento() {
return {
obterItem,
salvarItem,
removerItem
}
}
Agora, vamos precisar construir cada uma dessas tarefas. Todas serão funções assíncronas:
async function obterItem() {
try { }
catch { }
}
O código parcial ficará dessa forma:
import AsyncStorage from '@react-native-async-storage/async-storage'
export default function Armazenamento() {
async function obterItem() {
try { }
catch { }
}
async function salvarItem() {
try { }
catch { }
}
async function removerItem() {
try { }
catch { }
}
return {
obterItem,
salvarItem,
removerItem
}
}
Vamos agora detalhar o funcionamento de cada algoritmo. Vamos considerar que a função irá trazer os itens ou retornará uma array vazia.
async function obterItem(chave) {
try {
const tokens = await AsyncStorage.getItem(chave);
return JSON.parse(tokens) || [];
}
Para completar a função de obter Item, vamos elaborar o catch. A função completa ficará assim:
async function obterItem(chave) {
try {
const tokens = await AsyncStorage.getItem(chave);
return JSON.parse(tokens) || [];
}
catch (erro) {
alert("Erro ao obter itens", erro)
return [];
}
}
Agora vamos elaborar a função de salvar itens:
async function salvarItem(chave, valor) {
try {
let tokens = await obterItem(chave);
tokens.push(valor);
await AsyncStorage.setItem(chave, JSON.stringify(tokens))
} catch (erro) {
alert("Erro ao salvar item", erro)
}
}
Para criar a função de remover o item, faremos uma construção diferente. Vamos atualizar nossos tokens filtrando aquele que queremos remover:
async function removerItem(chave, item) {
try {
let tokens = await obterItem(chave);
let tokensAtualizados = tokens.filter((tokens) => {
return (tokens !== item)
})
} catch (erro) {
alert("Erro ao remover item", erro)
}
}
A variável tokensAtualizados receberá todos os tokens salvos exceto aquele que escolhemos remover.
Para completar, precisamos atualizar nosso Armazenamento inserindo a seguinte instrução na função:
await AsyncStorage.setItem(chave, JSON.stringify(tokensAtualizados))
return tokensAtualizados;
Então, a função completa para remover um item fica assim:
async function removerItem(chave, item) {
try {
let tokens = await obterItem(chave);
let tokensAtualizados = tokens.filter((tokens) => {
return (tokens !== item)
})
await AsyncStorage.setItem(chave, JSON.stringify(tokensAtualizados))
return tokensAtualizados;
} catch (erro) {
alert("Erro ao remover item", erro)
}
}
E assim terminamos o nosso hook para Armazenamento. Segue abaixo o código completo:
import AsyncStorage from '@react-native-async-storage/async-storage'
export default function Armazenamento() {
async function obterItem(chave) {
try {
const tokens = await AsyncStorage.getItem(chave);
return JSON.parse(tokens) || [];
}
catch (erro) {
alert("Erro ao obter itens", erro)
return [];
}
}
async function salvarItem(chave, valor) {
try {
let tokens = await obterItem(chave);
tokens.push(valor);
await AsyncStorage.setItem(chave, JSON.stringify(tokens))
} catch (erro) {
alert("Erro ao salvar item", erro)
}
}
async function removerItem(chave, item) {
try {
let tokens = await obterItem(chave);
let tokensAtualizados = tokens.filter((token) => {
return (token !== item)
})
await AsyncStorage.setItem(chave, JSON.stringify(tokensAtualizados))
return tokensAtualizados;
} catch (erro) {
alert("Erro ao remover item", erro)
}
}
return {
obterItem,
salvarItem,
removerItem
}
}
Vamos agora atribuir a função de salvar senha ao modal.js.
Primeiro vamos adicionar o import para consumir o Armazenamento:
import Armazenamento from '../hooks/bancoTokens'
Em seguida vamos informar na área de funções o uso da função salvarItem que vem lá do armazenamento:
const { salvarItem } = Armazenamento();
Em seguida, vamos criar a função assíncrona que salva, informa e fecha o modal:
async function salvarToken() {
await salvarItem("@token", token)
alert(`Token ${token} salvo com sucesso`)
fechar();
}
Por fim, vamos atribuir a função ao botão de Salvar:
onPress={salvarToken}
📱 Pausa para um front-end ☕
Precisamos fazer o token salvo apareça na tela Minhas senhas, então vamos criar um novo componente que será usado para receber o token:

No arquivo tokenView.js vamos montar a seguinte estrutura:
import React from "react";
import { Text, StyleSheet, Pressable } from "react-native";
export function CaixaToken() {
return (
<Pressable style={estilos.caixa}>
<Text style={estilos.text}>
Token salvo
</Text>
</Pressable>
)
}
const estilos= StyleSheet.create({
caixa:{
backgroundColor:"#0e0e0e",
padding: 14,
width: "100%",
marginBottom: 14,
borderRadius:8,
flexDirection:"row",
alignItems:"center",
justifyContent:"space-between"
},
text:{
color:"#fff"
}
})
🪄 De volta ao Back-end 🎩
Vamos agora trabalhar no arquivo paginaSenhas.js
Como queremos consumir o armazenamento, vamos iniciar realizando o import:
import Armazenamento from '../hooks/bancoTokens';
Também queremos trazer o componente CaixaToken que vai receber o texto.
import { CaixaToken } from '../components/tokenView';
Para poder manipular a lista de tokens com o useState, vamos inserir o import:
Considerando que iremos usar as funções obterItem e removerItem, vamos inicializa-las em nossa estrutura:
const { obterItem, removerItem } = Armazenamento();
/* entenda:
const obterItem = Armazenamento().obterItem;
const removerItem = Armazenamento().removerItem;
Não confunda o código acima com useState, pois trata-se de uma variável desestruturada
*/
import { useState } from 'react';
Assim podemos inserir a seguinte instrução:
const [listaTokens, defListaTokens] = useState([]);
Vamos fazer com que o carregamento dos tokens ocorra somente quando acessarmos a tela das minhas senhas. Para isso usaremos o useEffect, que irá solicitar o procedimento.
Para usar o useEffect, vamos adiciona-lo ao import:
import { useState, useEffect } from 'react'
Para conseguir determinar se a tela das minhas senhas está ativa ou não, vamos importar uma nova dependência:
import { useIsFocused } from '@react-navigation/native';
E então vamos inicializa-la também:
const telaAtiva = useIsFocused();
Até o momento estamos com esse resultado no arquivo paginaSenhas:
import { View, StyleSheet, Text } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import Armazenamento from '../hooks/bancoTokens';
import { useState, useEffect } from 'react';
import { CaixaToken } from '../components/tokenView';
import { useIsFocused } from '@react-navigation/native';
export function PaginaSenhas() {
const { obterItem, removerItem } = Armazenamento();
const [listaTokens, defListaTokens] = useState([]);
const telaAtiva = useIsFocused();
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={estilos.header}>
<Text style={estilos.title}>
Minhas senhas
</Text>
</View>
</SafeAreaView>
)
}
const estilos= StyleSheet.create({
header: {
padding: 14,
paddingTop: 58,
backgroundColor: "#392de9"
},
title: {
fontSize: 18,
fontWeight: "bold",
color: "#FFF"
}
})
Para trabalhar com o useEffect, estudaremos sua estrutura. Basicamente ele recebe 2 condições; um arrow function que executa as ações, e um array de gatilho:
useEffect(() => { }, []);
Primeiramente vamos passar o gatilho da tela ativa:
useEffect(() => { }, [telaAtiva]);
Agora vamos trabalhar nas funções, iniciando com a obtenção dos tokens:
async function carregaTokens() {
const tokens = await obterItem("@token");
defListaTokens(tokens);
}
Assim que os tokens forem obtidos do armazenamento, executaremos o carregaTokens. Nosso useEffect completo ficará assim:
useEffect(() => {
async function carregaTokens() {
const tokens = await obterItem("@token");
defListaTokens(tokens);
}
carregaTokens()
}, [telaAtiva]);
Para gerar a função que deleta um item da lista, vamos usar o seguinte código:
async function deletarToken(item) {
const tokens = await removerItem("@token", item)
defListaTokens(tokens)
};
Para podermos exibir a lista de Tokens, vamos fazer uso do FlatList:
import { View, StyleSheet, Text, FlatList } from "react-native";
E inserir a visualização da lista. Repare que a exibição do FlatList carrega a CaixaToken com dois parâmetros; exibir o token e removerToken
<View style={estilos.content}>
<FlatList
style={{ flex: 1, paddingTop: 14, }}
data={listaTokens}
keyExtractor={(item) => String(item)}
renderItem={({ item }) => <CaixaToken
token={item}
removerToken={() => deletarToken(item)}
/>}
/>
</View>
E estilizar a nova View, adicionando o seguinte código:
content: {
flex: 1,
paddingLeft: 14,
paddingRight: 14,
}
Agora iremos passar os tokens da FlatList para dentro do componente CaixaToken. Então no arquivo tokenView.js vamos modificar o código, acrescentando as variáveis:
export function CaixaToken({token, removerToken}) {
return (
<Pressable style={estilos.caixa} onLongPress={removerToken}>
<Text style={estilos.text}>
{token}
</Text>
</Pressable>
)
}
Note que agora passamos as variáveis token e removerToken para serem consumidas no FlatList.
🎉Parabéns, você chegou ao final!!
⚔️Super Desafio!
Use os conhecimentos adquiridos para alterar os códigos e chegar na aparência abaixo:

🥉O ícone usado se chama “trash” e faz parte da biblioteca Ionicons;
🥉O ícone da lixeira deverá ter a função de remover o Token.
🥈O parâmetro onLongpress deverá ser usado para copiar o token para área de transferência.
🥇Configure um setTimeout com delay de 300ms para animar o efeito fade do Touchable durante a exclusão do token
Share this content:
Publicar comentário