flux javascript react

Programação front end com react e flux – calculadora parte 2

Compartilhe os ensinamentos do mestre

Lá vem mais um pouco de programação front end

Vamos lá galera é hora de mais um tutorial de programação front end. Este post é a parte dois da nossa introdução ao React com Flux. Se você perdeu a parte 1 então dá uma conferida lá primeiro.

Calculadora em javascript com React e Flux – parte 1

No  tutorial anterior criamos nosso projeto e nossos componentes, mas não definimos nenhum comportamento para ele. Ou seja temos apenas as views da calculadora, porém ainda não é possível fazer nenhum cálculo nela. Neste tutorial vamos ver como funcionam os stores do Flux.

Caso você queira baixar o projeto pronto você pode clonar este repositório aqui

https://github.com/victorrseloy/tutorial-react-e-flux-calculadora

Os componentes do Flux

O Flux introduz 3 novos conceitos na arquitetura da nossa aplicação.

  • Stores
  • Actions
  • Dispatcher

Vamos começar entendendo o propósito dos Stores na aplicação.

Programação front end com flux

Stores

Os stores são similares aos models ou view models das aplicações tradicionais, porém possuem duas diferenças essenciais.

A primeira delas é a capacidade de emitir eventos para objetos que se inscrevam afim de receber atualizações dos Stores. Em aplicações React com Flux as views serão irão se inscrever para receber essas mudanças, assim toda vez que houver uma mudança nos stores as views correspondentes serão notificadas e serão renderizadas novamente para refletir tais mudanças. Aí você estar se perguntando “aaaaa mas isso não vai ficar lento se ele for renderizar o componente todo por causa de qualquer mudança?” Lembre-se do que eu disse na intrudução ao react. Quando algo muda no componente primeiro a mudança vai ocorrer no virtual DOM então o react vai calcular a forma mais eficiente de atualizar o DOM real. Ou seja isso não será pesado.

A segunda diferença é que os Stores também reagem a eventos recebidos pelo Dispatcher da aplicação. Mas vamos por partes, eu vou explicar mais sobre o Dispatcher no próximo post da série .

Stores na prática

Chega de história e vamos meter a mão na massa, hora de criar o store da nossa calculadora. Vou descrever o comportamento da calculadora e conforme faço isso vou ir listando as propriedades que vamos precisar criar.

A nossa calculadora vai precisar armazenar 5 informações para funcionar. A primeira é a mais auto evidente de todas é o valor do display. A segunda também tem a ver com o que é exibido no display, quando o usuário clicar na vírgula precisamos entrar no modo “decimal” de operação ou seja todos os números digitados serão adicionados após a vírgula. A terceira variável guardará a operação sendo executada. A quarta vai guardar o último valor digitado / resultado da operação anterior, afinal de contas precisamos de dois valores para executar a operação corrente(A do visor e o valor anterior). E finalmente a quinta será uma flag que marcará se a calculadora precisa ter o visor limpo quando o usuário apertar o próximo botão.

Lembrem-se do que eu disse que os stores precisam ser capazes de emitir eventos, para tal vamos simplesmente herdar da classe EventEmmiter do pacote events presente no Node.js. Então vou criar um Store com essas cinco propriedades e toda vez que alguma delas for alterada vou emitir um evento.

Crie um diretório chamada flux abaixo dentro do diretório src

Agora dentro do diretório flux crie um arquivo chamado CalculadoraStore.js

Eis o conteúdo desse arquivo:

CalculadoraStore.js:

import EventEmmiter from 'events'

const CHANGE = 'change'

let _store = {
    valorDoDisplay:'0',
    resultadoUltimaOperacao:0,
    limparVisor:false,
    operacaoAritmetica: undefined,
    modoDeEntradaDecimal: false,
}

class CalculadoraStore extends  EventEmmiter{

    getValorDoDisplay(){
         return _store.valorDoDisplay;
    }

    setValorDoDisplay(valor){
        _store.valorDoDisplay = valor;
        this.emit(CHANGE);
    }

    getResultadoUltimaOperacao(){
        return _store.resultadoUltimaOperacao;
    }

    setResultadoUltimaOperacao(valor){
        _store.resultadoUltimaOperacao = valor;
        this.emit(CHANGE);
    }

    getLimparVisor(){
        return _store.limparVisor;
    }

    setLimparVisor(valor){
        _store.limparVisor = valor;
        this.emit(CHANGE);
    }

    getOperacaoAritmetica() {
        return _store.limparVisor;
    }

    setOperacaoAritmetica(valor){
        _store.operacaoAritmetica = valor;
        this.emit(CHANGE);
    }

    getModoDeEntradaDecimal(){
        return _store.modoDeEntradaDecimal;
    }

    setModoDeEntradaDecimal(valor){
        return _store.modoDeEntradaDecimal = valor;
        this.emit(CHANGE);
    }

    getState(){
        return _store
    }
}

export let calculadoraStore = new CalculadoraStore()
window.calculadoraStore = calculadoraStore

Repare que no nosso store toda vez que algo muda emitimos o evento change, assim os componentes registrados para receber atualizações desse store sempre serão notificados.

Outro ponto de atenção é o fato de que eu não declarei as propriedades do store dentro dele mas sim em um objeto separado no começo do arquivo. Fiz isso porque a ideia é que o nosso store seja um singleton ou seja deve haver apenas uma instância dele em tempo de execução. Eu reforço essa minha intenção no export pois estou criando e exportando uma instância única do Store, ou seja sempre que houver um require o mesmo objeto será retornado.

window.calculadoraStore = calculadoraStore

Essa linha de código faz com que o store fique globalmente disponível, eu fiz isso apenas para fins de teste. Em uma aplicação real isso não deve ser feito.

Chamando o store na programação front end da nossa calculadora

Ok, agora que temos nosso store pronto vamos fazer algumas alterações nos nossos componentes para poder usá-lo. Primeiro vamos atualizar nosso visor para receber uma propriedade através do objeto props para mostrar o valor baseado no que receber do componente pai.

Nós até poderiamos colocar a lógica para acessar o store dentro do próprio Visor.js, mas é uma boa prática separar os componentes react em “componentes burros” cujo propósito é apenas cuidar da renderização. E controller views  que são componentes inteligentes compostos de vários componentes menores. As controller views são os responsáveis por receber os eventos dos Stores, atualizar seu próprio estado e passar as atualizações para os componentes filhos através das props.

Abra seu arquivo Visor.js e o altere para que ele fique assim:

import React from 'react'

export default class Visor extends React.Component{

    render(){
        return (
            <div id="visor">
                <h1>{this.props.valor}</h1>
            </div>
        )
    }
}

comparando o arquivo atual com o nosso arquivo anterior a mudança que fizemos foi esta aqui:

<h1>0</h1>  mudou para <h1>{this.props.valor}</h1>

Agora vamos alterar o arquivo Calculadora.js para enviar os valores necessários ao visor e receber as alterações do Store.

Abra seu arquivo Calculadora.js e altere o conteúdo para que ele fique assim:

import React from 'react'
import Visor from './Visor'
import Teclado from './Teclado'

import {calculadoraStore} from './../flux/CalculadoraStore'

export default class Calculadora extends React.Component{

    constructor(props){
        super(props)
        this.state = calculadoraStore.getState()
    }

    componentWillMount(){
        calculadoraStore.on('change', ()=>{
            this.setState(calculadoraStore.getState())
        })
    }

    render(){
        return (
            <div id="calculadora">
                <Visor valor={this.state.valorDoDisplay}/>
                <Teclado/>
            </div>
        )
    }
}

 

Os pontos importantes a serem notados aqui são:

No construtor estamos setando um estado inicial, através do nosso store.

constructor(props){
        super(props)
        this.state = calculadoraStore.getState()
    }

sobrescrevemos o método componentWillMount() para registrar nosso listener nos eventos de change do calculadoraStore.

componentWillMount(){
        calculadoraStore.on('change', ()=>{
            this.setState(calculadoraStore.getState())
        })
    }

O método  componentWillMount() faz parte do ciclo de vida dos componentes react e é invocado apenas uma vez antes da primeira renderização do componente, por isso ele é o lugar ideal para registrar esse tipo de código.

E finalmente outra mudança importante está na forma como passamos valor para o componente visor:

<Visor valor={this.state.valorDoDisplay}/>

 

Testando as mudanças

abra o diretório raíz da sua aplicação e execute o comando

npm start

Após isso abra seu navegador e acesse http://localhost:8080/, se tudo deu certo você irá ver a calculadora exatamente como ela estava antes

 

Calma jovem agora vem a parte divertida, abra seu console do google chrome(leia aqui como fazer isso caso não saiba https://developer.chrome.com/devtools) e clique na guia console. Como expusemos o calculadoraStore você vai poder chamar os métodos dele diretamente do console. Insira esse código aqui no seu console e pressione enter:

calculadoraStore.setValorDoDisplay('17')

Voila(isso é francês 😀 lol) os valores do visor da nossa calculadora estão mudando agora.

O que esperar do próximo tutorial

No próximo tutorial vou explicar o que é o dispatcher e o que são as Actions e finalmente nossa calculadora irá começar a fazer alguns cálculos. Leia aqui a continuação:

Calculadora em javascript com React e Flux – parte 3

Não esqueça de se inscrever na nossa newsletter para receber as últimas atualizações.