Skip to content
This repository has been archived by the owner on Jun 27, 2019. It is now read-only.

React Native Tutorial

José Chaves Neto edited this page Apr 29, 2019 · 10 revisions

Introdução

React Native é um Framework Javascript desenvolvido pelo Facebook para construção de Apps mobile nativos. Ele faz uso do Framework React e oferece uma grande quantidade de componentes e API's.

To-do App

Neste tutorial iremos fazer um App simples para registro e visualizações de tarefas, utilizando dos recursos disponibilizados pelo React Native e com o serviço Cloud Firestore.

Primeiro é necessário ter todo o ambiente configurado para poder construir o App. Siga o tutorial dessa wiki, para fazer a configuração do seu ambiente.

Para começar é necessário primeiro que você faça o clone do seguinte repositório: https://github.com/netochaves/TodoDemo neste repositório terá os arquivos iniciais para o projeto. Feito o clone do repositório, abra a pasta do projeto com um terminal e digite o seguinte comando:

npm install

Este comando irá instalar todos os módulos necessários para o projeto.

Agora abra o projeto com o seu editor de texto ou IDE, crie um novo arquivo Todos.js na raiz do projeto, agora no arquivo index.js altere para que ele aponte para o novo arquivo criado

import { AppRegistry } from "react-native"
import Todos from "./Todos"
import { name as appName } from "./app.json"

AppRegistry.registerComponent(appName, () => Todos)

Aqui estou importando o arquivo Todos, e colocando para que ele seja mostrado quando o App inicializar.

Agora configure uma classe js basica no Todos.js

import React from 'react';
class Todos extends React.Component {
  render() {
    return null;
  }
}
export default Todos;

render() é o método que renderiza a tela cada vez que seu estado muda, por enquanto não estamos renderizando nada.

Criando a estrutura do Cloud Firestore

O Cloud Firestore permite que documentos (Objetos de data) sejam registrados em coleções. Nosso Todo App vai ter apenas uma lista de todos, esses todos serão armazenados em uma coleção de "todos" no Firestore. Cada documento representa um todo e terá os seus dados, no nosso caso apenas o titulo e o status ("complete").

O primeiro passo é criar uma referência para a coleção, que pode ser usado dentro do nosso componente para enviar requisições e receber respostas. Vamos importar o react-native-firebase e criar essa referência no construtor do componente.

import React from 'react';
import firebase from 'react-native-firebase';
class Todos extends React.Component {
  constructor() {
    super();
    this.ref = firebase.firestore().collection('todos');
  }
...

Criando a UI

Para não longar muito esse tutorial iremos utilizar styles in-line mas você deve utilizar StyleSheet para os seus aplicativos.

A UI vai ser simples: uma scrollable list de todos e um textInput com um Button para adicionar novos todos. Vamos adicionar nossa UI ao método render()

render() {
  return (
    <View>
      <ScrollView>
        <Text>List of TODOs</Text>
      </ScrollView>
      <TextInput
        placeholder={'Add TODO'}
      />
      <Button
        title={'Add TODO'}
        disabled={true}
        onPress={() => {}}
      />
    </View>
  );
}

É necessário que se faça os imports dos componentes utilizados na UI, portanto nas primeiras linhas do arquivo, adicione:

import { ScrollView, View, Text, TextInput, Button } from 'react-native'

Com isso rode o comando react-native run-android e você deverá ver uma tela como a seguinte:

Agora precisamos pegar o texto digitado no textInput para que possamos enviar o valor para o Cloud Firestore quando o botão for pressionado.

Adicione o state para o construtor:

constructor() {
    super();
    this.ref = firebase.firestore().collection('todos');
    this.state = {
        textInput: '',
    };
}

Adicione o método updateTextInput() para atualizar o state quando o valor de textInput for alterado

updateTextInput(value) {
    this.setState({ textInput: value });
}

Adicione as seguintes propriedades no TextInput para que quando o seu valor for alterado acione o metodo updateTextInput()

<TextInput
    placeholder={'Add TODO'}
    value={this.state.textInput}
    onChangeText={(text) => this.updateTextInput(text)}
/>

Mude o valor da propriedade disabled para que o botão seja ativado baseado no valor do campo textInput

<Button
    title={'Add TODO'}
    disabled={!this.state.textInput.length}
    onPress={() => {}}
/>

Seu App agora deve responder as mudanças no texto:

Adicionando um novo documento

Para adicionar um novo documento para a coleção, nós podemos chamar o método add na referência da coleção. Vamos criar um método addTodo() para adicionar o todo.

addTodo() {
  this.ref.add({
    title: this.state.textInput,
    complete: false,
  });
  this.setState({
    textInput: '',
  });
}

Vamos configurar o botão para acionar o método

<Button
    title={'Add TODO'}
    disabled={!this.state.textInput.length}
    onPress={() => this.addTodo()}
/>

Quando o botão é pressionado o novo todo é enviado ao Cloud Firestore e adicionado na coleção. Então é resetado o valor de TextInput no state. O método add é assincrono e retorna uma Referência de Documento de uma promise se requerido.

O novo documento adicionado no Cloud Firestore

Escutando atualizações na coleção

Já conseguimos adicionar todos a nossa coleção, mas agora precisamos mostrar esses todos na tela do App. Cloud firestore oferece dois métodos para isso, get() que retorna os documentos de uma vez e onSnapshot() que fornece autalizações em tempo real quando um documento é alterado na coleção (adição, remoção e update). Para o nosso TODO App, nós queremos resultados em tempo real, então vamos implementar isso.

Adicione um loading e todos ao componente.

constructor() {
    super();
    this.ref = firebase.firestore().collection('todos');
    this.unsubscribe = null;
    this.state = {
        textInput: '',
        loading: true,
        todos: [],
    };
}

Nós precisamos de um loading para indicar para o usuário que a primeira conexão com o Cloud Firestore ainda não foi completada. Também adicionamos um unsubscribe atributo ao state que iremos ver o uso mais a frente.

Agora, iremos criar o método que fica escutando por alterações e fazer a iteração em cada documento, esse método ficará dentro do método de ciclo de vida componentDidMount(), este método será acionado toda vez que o componente for montado e isso acontece a cada vez que o state é atualizado. Para saber mais sobre os métodos de ciclo de vida, veja: https://reactjs.org/docs/state-and-lifecycle.html

componentDidMount() {
    this.unsubscribe = this.ref.onSnapshot(querySnapshot => {
      const todos = []
      querySnapshot.forEach(doc => {
        const { title, complete } = doc.data()
        todos.push({
          key: doc.id,
          doc,
          title,
          complete
        })
      })
      this.setState({ todos, loading: false })
    })
  }

Utilizamos o Snapshot método forEach para iterar sobre cada documento na ordem que eles são armazenados no Cloud Firestore, guardamos o ID (.id) e os dados (.data) do documento, também guardamos o DocumentSnapshot no state para acessar isso diretamente.

Toda vez que um documento for adicionado, alterado ou removido esse método será atualizado e irá atualizar o state da aplicação.

Exibindo os todos

Agora que possuimos os todos carregados no state iremos exibi-los na tela. Para isso utilizaremos do componente FlatList pois o ScrollView pode causar problemas de performance.

Atualizando o loading

render() {
  if (this.state.loading) {
    return null; // or render a loading icon
  }

Exibe os todos em uma FlatList usando o todos state.

import { FlatList, Button, View, Text, TextInput } from 'react-native';
import Todo from './Todo'; // we'll create this next
...
render() {
  if (this.state.loading) {
    return null
  }
  return (
    <View style={{ flex: 1 }}>
        <FlatList
          data={this.state.todos}
          renderItem={({ item }) => <Todo {...item} />}
        />
        <TextInput
            placeholder={'Add TODO'}
            value={this.state.textInput}
            onChangeText={(text) => this.updateTextInput(text)}
        />
        <Button
            title={'Add TODO'}
            disabled={!this.state.textInput.length}
            onPress={() => this.addTodo()}
        />
    </View>
  )
}

Você pode perceber que estamos renderizando um componente Todo para cada item, abaixo estará o código desse componente, percebe-se também que este componente é um PureComponent que fornecerá uma grande melhoria de performance pois só será atualizado quando os valores de title e/ou complete serem alterados.

crie o arquivo Todo.js na raiz do projeto:

import React from 'react';
import { TouchableHighlight, View, Text } from 'react-native';
export default class Todo extends React.PureComponent {
    // toggle a todo as completed or not via update()
    toggleComplete() {
        this.props.doc.ref.update({
            complete: !this.props.complete,
        });
    }

    render() {
        return (
          <TouchableHighlight
            onPress={() => this.toggleComplete()}
          >
              <View style={{ flex: 1, height: 48, flexDirection: 'row', alignItems: 'center' }}>
                  <View style={{ flex: 8 }}>
                      <Text>{this.props.title}</Text>
                  </View>
                  <View style={{ flex: 2 }}>
                      {this.props.complete && (
                          <Text>COMPLETE</Text>
                      )}
                  </View>
              </View>
          </TouchableHighlight>
        )
    }
}

Este componente apenas exibe o titulo do todo e se ele está completo ou não. Ele está dentro de um componente TouchableHighlight que irá criar um efeito quando o componente for selecionado, ao acionar o componente podemos pegar a referência do documento diretamente da propriedade doc que foi passada anteriormente e atualizar esse documento utilizando do método update (Que também é assíncrono caso você queira tratar erros).

Agora podemos selecionar um todo, para mudar o seu estado para completo ou remover esse estado, e isso é mostrado em tempo real para o usuário, pois nosso método subscription atualiza o state toda vez que houver uma alteração no Cloud Firestore, cool right?

Isso é apenas 1% do que o react-native pode fazer junto com o Firebase para os seus Apps. Deixarei alguns links abaixo caso você queira continuar se aventurando nesse mundo do React-native. Let's Code!!

React native official docs - https://facebook.github.io/react-native/docs/getting-started

React native course - Free - https://www.youtube.com/watch?v=frvXANSaSec

React native guide - https://www.reactnative.guide

Code Camp - https://www.freecodecamp.org