Como construir a sua primeira aplicação com Elm — Parte 1

No meu último post, Elm: Programação Funcional no Front-End do jeito certo, falei sobre as principais características e vantagens da linguagem mas (praticamente) sem mostrar código. Ou seja, dei ênfase no porquê e não no como.

Neste post irei focar no como e mostrar na prática o passo a passo para criar uma aplicação bem simples com Elm.


Introdução

Neste post não iremos fazer um setup da linguagem, mas se você deseja ter o Elm instalado e poder criar suas próprias aplicações, sugiro seguir o guia oficial.

Vamos construir uma aplicação bem simples, mas que demonstra diversos aspectos da linguagem: um contador.

Contador simples

Na documentação do Elm podemos ver um exemplo bem parecido.

Modularização

Para importarmos módulos com Elm, basta adicionarmos import seguido do nome do módulo que desejamos. 
Como vamos utilizar HTML na aplicação vamos importar o módulo Html, um dos módulos oficiais da linguagem, assim:

import Html

Dessa forma podemos invocar funções do módulo Html, dessa forma:

Html.text 'Olá'

Mas repetir o nome do módulo toda vez que formos invocar uma função dele pode ser cansativo. Podemos evitar essa repetição alterando o import, expondo as funções que estamos usando:

import Html exposing (text)
text 'Olá'

Podemos também expor todas as funções de um módulo, sem precisar nomear cada uma delas:

import Html exposing (..)
text 'Olá'

Com isso já temos a primeira linha da nossa aplicação:

import Html exposing (..)

Model

O nosso model será extremamente simples. Como temos um contador, o modelo será um valor inteiro simples, inicializado com zero:

model = 0

Opcionalmente, podemos deixar explícita a tipagem do modelo, fazendo uma anotação de tipo (ou Type Annotation), dessa forma:

model: Int
model = 0

Se não fizermos a anotação de tipo, o compilador irá automaticamente inferir os tipos.

Com isso nossa aplicação, está assim:

import Html exposing (..)
model: Int
model = 0

View

Não faz sentido construir um contador sem que seja possível visualizá-lo. Precisamos então da nossa view, que será simplesmente uma função que converterá código Elm em HTML.

Para refrescar a memória, é isso que precisamos:

Ou seja, dois botões: um para incrementar e um para decrementar, e um elemento de texto com o valor do contador.

Podemos então implementar a função que irá representar a view dessa forma:

view model =
div []
[ button [] [ text "-" ]
, div [] [ text (toString model) ]
, button [] [ text "+" ]
]

O código acima pode parecer complicado, mas vamos desmitificá-lo passo a passo.

1. view model =
2. div []
3. [ button [] [ text "-" ]
4. , div [] [ text (toString model) ]
5. , button [] [ text "+" ]
6. ]

Na linha 1 (em negrito), estamos criando uma função chamada view, que recebe como parâmetro o nosso model.

Essa nova função view receberá uma div, que também é uma função:

1. view model =
2. div []
3. [ button [] [ text "-" ]
4. , div [] [ text (toString model) ]
5. , button [] [ text "+" ]
6. ]

A função div recebe dois parâmetros:
1. O primeiro é uma lista de atributos (id, class, style, etc), no nosso caso ela vai ficar vazia porque não precisamos de nenhum atributo. 
2. E o segundo é uma lista de elementos filhos dessa div.

1. view model =
2. div []
3. [ button [] [ text "-" ]
4. , div [] [ text (toString model) ]
5. , button [] [ text "+" ]
6. ]

Os filhos da div (da linha 2) serão: 
1. Um botão para decrementar o contador (linha 3)
2. Uma outra div com o valor do contador (linha 4)
3. Um botão para incrementar o contador (linha 5)

Como o nosso model é um Int, não podemos simplesmente usá-lo na função text, porque ela espera uma String como parâmetro. Por isso convertemos o valor do model de um Int para uma String:

1. view model =
2. div []
3. [ button [] [ text "-" ]
4. , div [] [ text (toString model) ]
5. , button [] [ text "+" ]
6. ]

Agora basta explicitarmos as anotações de tipo da view
Se analisarmos a função view, verificamos que ela espera um model como parâmetro (que é simplesmente um Int) e retorna um Html como resultado. 
Isso resultaria em:

view: Int -> Html
view model =
div []
[ button [] [ text "-" ]
, div [] [ text (toString model) ]
, button [] [ text "+" ]
]

Porém isso está incorreto por um pequeno detalhe:

view: Int -> Html Msg

Mais pra frente vamos entender esse Msg obscuro, mas quero que nesse momento você foque apenas que a view recebe o model e retorna um Html.

Portanto, nossa aplicação completa se encontra dessa maneira:

import Html exposing (..)

model: Int
model = 0

view: Int -> Html Msg
view model =
div []
[ button [] [ text "-" ]
, div [] [ text (toString model) ]
, button [] [ text "+" ]
]

Type Aliases

Uma boa convenção da comunidade Elm, é criar Type Aliases para facilitar a leitura das anotações de tipo criadas.

No nosso caso, podemos criar um Alias para o modelo dessa forma:

type alias Model = Int

Ou seja, em todos os lugares da nossa aplicação que estamos usando o Int para nos referir ao model, podemos agora usar o próprio Model. Facilitando muito a leitura, principalmente em aplicações grandes.

Atualizando então a aplicação, temos:

import Html exposing (..)

type alias Model = Int
model: Model
model = 0

view: Model -> Html Msg
view model =
div []
[ button [] [ text "-" ]
, div [] [ text (toString model) ]
, button [] [ text "+" ]
]

Essa foi apenas a Parte 1.
Clique aqui para ler também a Parte 2.


Se você gostou do post não se esqueça de dar um ❤ aqui embaixo!
E se quiser receber de antemão mais posts como esse,
assine nossa newsletter.

Seja um apoiador, doe BitCoins: 1BGVKwjwQxkr3w1Md2X8WHAsyRjDjyJiPZ

JSCasts

É difícil encontrar conteúdo bom e atualizado em português. Com isso em mente criamos o JSCasts, onde você vai se manter em dia com o JavaScript e todo o seu ecossistema de forma fácil e interativa.

Cursos:

Obrigado por ler! ❤