Back-End

31 ago, 2017

Entregando um aplicativo ReasonReact

Publicidade

Estou apaixonado pela família ML de linguagens de programação por algum tempo. No entanto, e além da Kata ocasional, nunca entreguei nada usando uma linguagem ML.

Dada a recente atividade na comunidade de Ocaml, no entanto – principalmente devido aos esforços de comunicação por trás do Reason do Facebook – me senti compelido a tentar novamente (depois de uma incursão muito curta durante o meu curso de graduação).

 

Começando e material de leitura

Passei pela configuração inicial do Reason na mesma época em que Jared Forsyth publicou um tutorial muito detalhado sobre como começar com ReasonReact e compilar Reason para o navegador usando BuckleScript.

Apesar de sua pouca idade, o BuckleScript é uma incrível tecnologia que irá (instantaneamente, se eu puder adicionar) compilar o código Ocaml (com built-in) de suporte para Reason, para JavaScript. O manual do BuckleScript, embora um pouco conciso no início, é uma referência fantástica ao trabalho com o compilador e tornou-se uma aba fixa no meu navegador logo que comecei esta jornada.

 

Próximas etapas e solução de problemas

Mas depois da configuração inicial, eu estava sozinho, e tive que começar em algum lugar. reason-scripts, um template personalizado para create-react-app, acabou sendo uma ótima maneira de desenvolver meu projeto sem o incômodo de escrever código bloilerplate, configurar ferramentas e gastar horas averiguando os erros mais ínfimos.

Como qualquer iniciante que atravessava os obstáculos de paradigmas desconhecidos, não demorou até eu encontrar algumas dificuldades. O que se segue é uma tentativa de documentar as armadilhas que me atrapalharam no início, o que espero seja útil para outros tentando descobrir erros de iniciantes à medida que começam com Reason (React).

 

A variável do tipo terrível não pode ser generalizada

Em seu tutorial, Jared descreve como fazer um componente stateful, mas quando tentei migrar o meu componente sem estado para um stateful, fui imediatamente saudado pela seguinte mensagem de erro, um pouco enigmática:

 

Module build failed: Error: File "/path/to/src/app.re", line 5, characters 16-51:
Error: The type of this expression,
       ('_a, ReasonReact.stateless, ReasonReact.noRetainedProps,
        ReasonReact.noRetainedProps)
       ReasonReact.componentSpec,
       contains type variables that cannot be generalized

 

A solução era simplesmente usar o estado em algum lugar em qualquer função do meu componente. Mesmo apenas desestruturando o estado do e.g.  – um simples argumento para render resolve o problema.

Agora, a razão pela qual isso acontece é bastante interessante: se você olhar para o tipo de ReasonReact.statefulComponent, existe um estado de variável de tipo. Essa é a variável a que o erro está se referindo: quando o estado não é usado dentro da definição do componente, o compilador não pode inferir o que queremos que seu tipo seja. Se usado explicitamente, então estamos literalmente dizendo o que essa variável de tipo deve ser.

Uma consideração interessante aqui é que ReasonReact.statelessComponent não possui esse problema. Se olharmos para a definição de tipo, é quase imediatamente óbvio por quê: não há variáveis de tipo à vista. O compilador sempre sabe que ele levará um argumento sem estado (que é definido acima no arquivo como sendo o tipo de unidade).

A equipe por trás do ReasonReact está bem ciente desse erro e de alguns outros casos limites na biblioteca e está trabalhando ativamente para corrigi-los no futuro próximo. Para mais informações, há uma seção sobre isso no FAQ Ocaml.

 

Módulos e capitalização

O Ocaml possui um sistema de módulo muito interessante. Em suma, os módulos são usados para agrupar definições relacionadas e podem ser arbitrariamente aninhados. Curiosamente, os arquivos também se tornam módulos, e um dos meus primeiros erros foi relacionado à sua capitalização ao abrir um módulo de um arquivo diferente.

Como parte do ReKeys, eu defino um arquivo chamado dom_utils.re para agrupar certas definições relacionadas à interação com DOM e eventos. Ao tentar abrir esse arquivo para consumo em outro arquivo, não consegui fazê-lo funcionar.

O motivo é que o módulo fornecido por um arquivo é reconhecido pelo compilador com a primeira letra (e somente a primeira letra) maiúscula. Então, domUtils.re torna-se DomUtils, mas dom_utils.re torna-se Dom_utils, e eu estava tentando abrir o Dom_Utils. Esse é um daqueles erros que nunca mais voltarei a fazer, mas foi uma dor de cabeça por um tempo!

 

Assinaturas de tipo inline

Tendo tentado outras linguagens na família ML, como Haskell, Elm ou PureScript, lutei inicialmente com a forma de anotar os tipos de minhas definições. Em Haskell, por exemplo, os tipos podem ser anotados acima da implementação de uma função, como abaixo:

 

foo :: Int -> Int
foo x = x + 1

 

No entanto, em Ocaml/Reason, anotar a função foo seria feito inline ou em um arquivo de interface .rei. Exemplo:

 

/* my_file.rei */
let foo: int => int;

/* inline, in a my_file.re file */
let foo: int => int = fun x => x + 1;

 

Pensamentos finais

No geral, minha experiência com Reason foi incrivelmente boa. Eu adoro como o compilador atua como alguém constantemente olhando por cima do meu ombro me dizendo as maneiras incríveis como posso estragar o que eu estou fazendo.

A comunidade Reason no Discord é extremamente útil e tem sido muito paciente com minhas constantes perguntas de novato sobre qualquer coisa referente a Ocaml/Reason.

Eu estou animado para continuar mexendo com Reason e, eventualmente, construir algo mais sério. Enquanto isso, sugiro que você o experimente.

O código para ReKeys é gratuito e open source no GitHub. Por favor, tweet para @anmonteiro90 com quaisquer dúvidas/comentários sobre o código ReKeys e/ou este artigo!

Bom hacking!

 

***

 

 faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://anmonteiro.com/2017/08/shipping-a-very-simplistic-reasonreact-app/