React – Hooks entendendo o conceito.

Em outubro de 2018 aconteceu nos Estados Unidos em Las Vegas, Nevada, a ReactConf e dentre as novidades uma que chamou a atenção e causou um burburinho na comunidade de desenvolvedores foi uma nova feature chamada de hooks.

Dependendo de quando estiver lendo este post, a implementação do hooks ainda estará em Alpha, ou seja, não faz parte da versão corrente da biblioteca.

Mas o que são Hooks?

Hooks são um conjunto de novas funcionalidades que dentre outras coisa permitem ao desenvolvedor controlar o state de uma forma mais simples, mais rápida e mais intuitiva.

Sua implementação deu-se a partir da versão 16.7.0-alpha.0 e a promessa é que o desenvolvedor consiga transitar gradativamente do padrão utilizado atualmente para o hooks sem Breaking Changes e sem quebra muito a cabeça, podendo no inicio até utilizar as duas formas.

Compreendendo o Hooks.

Para entendermos esta nova feature vamos criar um projeto chamado todo-hooks.

Configurando o projeto.

Eu criei usando o create-react-app, pois sou preguiçoso e não queria ter o trabalho de configurar o webpack.

create-react-app todo-hooks

Se precisar relembrar como instalar o create-react-app e como criar um projeto leia, React – Primeiros Passos e React – Criando o primeiro componente.

Feito isso temos que alterar a versão do react e do react-dom, pois na data que criei este exemplo em Novembro de 2018 a versão do react instalada ainda não possuía os hooks.

Após instalado vamos entrar na pasta do projeto.

cd todo-hooks

E alterar as versões.

npm install react@16.7.0-alpha.0 --save   
npm install react-dom@16.7.0-alpha.0 --save

Fica a sua livre escolha deletar ou não os arquivos que não vamos usar, como também fica criar uma pasta de componentes para guardar todos os nossos componentes dentro.

Como não sou um primor em CSS utilizei este exemplo de todo do site w3schools e adaptei para o nosso projeto.

Não se preocupe com o CSS que ele estará disponível no download junto com todo o projeto no final da página.

Sem enrolar mais vamos ao código.

App.js

app

Aqui não existe mistério, o arquivo app é básico, apenas chama a TodoApp e renderiza na tela.

todo.js

todo1

Neste primeiro pedaço do arquivo todo.js importamos o useState do react e também  o componente que usaremos para mostrar a lista na tela.

Perceba que no começo do componente que não é uma classe e sim uma função definimos nosso estado da seguinte forma:

const [text, setText] = useState('');
const [items, setTodo] = useState([]);

Estamos indicando que os atributos do state que serão modificados são o text e o items. E as funções que serão responsáveis por modificar estes atributos são a setText e a setTodo.

Para compararmos, no contexto atual, ou seja, na versão corrente, teríamos algo como:

constructor(props) {
  super(props);
  this.state = {
    text: '',
    items: []
  };
}
this.setState({
  text: e.target.value
});
this.setState({
  items: items.concat(newItem)
});

toogle

A função toogleChecked() varrerá os itens e alterará aquele que foi clicado para que ele seja formatado com “text-decoration: line-through”.

A função removeItem() varrerá os itens e retornará os que forem diferentes do id passado, sendo assim, retirando da lista de todo aquele que foi clicado.

return

No código acima apenas renderizamos os elementos na tela, não tem nenhuma novidade quanto a forma anterior.

todoList.js

todoItem

O componente todoList é bem simples e serve apenas para varrermos os itens que se encontram no todo.

todoItem.js

todoItemjs

E por fim o todoItem que será responsável por cada parte do lista, marcando como feito ou deletando os itens.

Lista de Hooks.

Os Hooks são classificados em básicos e adicionais da seguinte forma:

Hooks básicos:

  • useState
  • useEffect
  • useContext

Hooks adicionais:

  • useReducer
  • useCallback
  • useMemo
  • useRef
  • useImperativeMethods
  • useMutationEffect
  • useLayoutEffect

Nós usamos apenas o useState no nosso exemplo.

Vamos acrescentar o useEffect apenas para indicar quantos itens já temos na lista ou qual item estamos adicionando nela.

useeffect

O resultado será:

Explicando o Hooks básicos.

O useState permite ler e armazenas as informações de maneira mais fácil e prática no state, eliminando alguns componentes de classes e substituindo por componentes funcionais.

O useEffect é o hook que utilizamos para executar funções que necessitam ou realizam algum efeito no componente, por exemplo, mutations, subscriptions, timers e logging. Tem o mesmo efeito que os componentDidMount e componentDidUpdate tem nas classes.

O useContext é um hook que permite você utilizar o Context passando o state entre os componentes Provider(de onde vem o state) e Consumer(quem receberá) de forma mais fácil e rápida.

Conclusão.

Os hooks vieram para ajudar ao desenvolvedor escrever componentes de forma mais simples e legível.

Não será preciso refatorar todas as classe e todo o projeto. Eles não quebrarão seu código e você poderá inclusive escrever das duas formas até se acostumar com eles.

Os hooks também não matarão o redux, inclusive podem ser utilizados com ele.

É preciso cuidado ao utilizar hooks como o useMutationEffect e o useLayoutEffect, pois os mesmo podem causar efeitos indesejados e problemas de desempenho.

Vídeo da ReactConf 2018

Referências:

Documentação oficial React Hooks (Inglês)

Showmethecode (Português)

Blog getty.io (Português)

Everything you need to know about react hooks(Inglês)

Template TODO w3schools(Inglês)

 

Anúncios

RxJS – O poder e a magia dos operadores

Nos posts anteriores, RxJS – Entendendo o conceito na prática e RxJS – Programação Reativa em JavaScript, falei sobre Observer, Observable, Subject e Subscribe, que são as bases do RxJS. No entanto não falei sobre os operadores, que são partes essenciais da biblioteca, que deixam o serviço mais fácil e permitem que o código assíncrono complexo seja facilmente composto de maneira declarativa.

Mas o que são os operadores?

Eles são métodos do objeto Observable, que chamados não alteram a instância Observable existente. Em vez disso, eles retornam um novo objeto Observable, cuja lógica de assinatura é baseada no primeiro Observable.

Em resumo um operador é uma função pura que cria um novo Observable com base no atual e o anterior permanece inalterado.

Criando testando os primeiros operadores.

Vamos criar um arquivo chamado operators1.js e nele vamos digitar o seguinte código:

const { from } = require('rxjs');
const { first, last } = require('rxjs/operators');

const source = from(['Corinthians', 'Palmeiras', 'São Paulo', 'Santos']);

const firstValue = source.pipe(first());
const lastValue = source.pipe(last());

firstValue.subscribe(val => console.log(`Primeiro Valor: ${val}`));
lastValue.subscribe(val => console.log(`Último Valor: ${val}`));

O exemplo acima é um dos mais básicos que podemos fazer com os operadores da biblioteca RxJS.

Nas duas primeiras linhas estamos apenas importando os operadores da biblioteca, como fizemos nos exemplos anteriores.

Já na terceira linha temos o operador from que é um operador de criação e:

  •  Pode ser usado para converter uma promisse em um observable;
  • Em arrays e iterables, todos os valores contidos serão emitidos como uma sequência;
  • Pode ser usado para emitir uma string como uma sequência de caracteres.

No nosso exemplo estamos usando o from para emitir uma sequência em uma array com o nome dos times.

Logo abaixo temos os operadores pipe, first e last.

O operador first é um operador de filtro e retorna o primeiro valor de uma sequência qualquer.

O operador last também é um operador de filtro e retorna o último valor de uma sequência.

Já o pipe é um caso à parte, com ele nós podemos vincular os operadores, incluindo combinar vários operadores e ter apenas um retorno.

Acalme os ânimos que faremos isso mais tarde, jovem padawan.

E as duas últimas linhas apenas imprimimos os valores no console.

Extraindo o poder dos operadores.

Vamos a um exemplo um pouco mais complexo. Imagine que estão 3 pessoas em um rodízio em uma pizzaria. As pizzas são divididas em doces e salgadas e são passadas aleatoriamente, podendo os sabores serem repetidos diversas vezes enquanto as pessoas estiverem ali.

Cada pessoa tem uma peculiaridade quanto as pizzas:

  • A primeira comerá apenas 5 pedaços de pizzas salgadas, desde que às pizzas não sejam apenas de Mussarela. E comerá também apenas 3 pedaços de pizzas doces.
  • Já a segunda pessoa comerá apenas as pizzas doces
  • E por fim a terceira pessoa comerá todas as pizzas que forem oferecidas, só que não repetirá nenhum sabor.

Parece um pouco complexo não é mesmo? Temos que fazer algumas validações, cada pessoa quer uma coisa, parece complicado.

Resumindo:

  • pessoa1: Apenas 5 salgadas diferentes de Mussarela e 3 doces;
  • pessoa2: Apenas pizzas doces;
  • pessoa3: Todas as pizzas sem repetir sabor

Ai que está o poder dos operadores da biblioteca RxJS. Eles diminuirão muito as linhas de código e deixarão ele bem mais legível.

Mãos na massa.

Separarei o código em várias partes para explicar minuciosamente, mas no link do GitHub, ele estará completo.

Vamos criar um arquivo chamado operators2.js e digitar o seguinte código:

const { Subject, from } = require('rxjs');
const { filter, take, distinct, skipWhile, merge } = require('rxjs/operators');

Essa primeira parte estamos importando os operadores que utilizaremos no código, então sem nenhuma novidade, já vimos isso outras vezes.

Vou explicar cada operador assim que ele aparecer.

class Pizza {
  constructor(name) {
    this.name = name;
  }
}

class PizzaSalagada extends Pizza {
  constructor(name) {
    super(name);
    this.type = 'Salgada'
  }
}

class PizzaDoce extends Pizza {
  constructor(name) {
    super(name);
    this.type = 'Doce'
  }
}

Esta segunda parte do código estamos definindo as classes que iremos utilizar para criar os objetos. Cada pizza terá o nome e o tipo, se é doce ou salgada.

Fiz assim, pois com o advento do ES6 e este cada vez mais presente no nosso dia a dia temos que nos acostumar com o uso das classes, que já estas são muito utilizadas em outras linguagens de programação como Java ou C# e também no TypeScript(TypeScript – Interface e Class).

Nossos objetos pizza serão simples, mas se criássemos objetos complexos esta também seria uma forma.

const pessoa2 = new Subject();
const pessoa3 = new Subject();

const pizzasPessoa1 = new Array();
const pizzasPessoa2 = new Array();
const pizzasPessoa3 = new Array();

const calabresa = new PizzaSalagada('Calabresa');
const mussarela = new PizzaSalagada('Mussarela');
const portuguesa = new PizzaSalagada('Portuguesa');
const aliche = new PizzaSalagada('Aliche');
const frango = new PizzaSalagada('Frango');
const pepperoni = new PizzaSalagada('Pepperoni');
const quatroQueijos = new PizzaSalagada('Quatro queijos');
const vegetariana = new PizzaSalagada('Vegetariana');

const prestigio = new PizzaDoce('Prestigio');
const chocolate = new PizzaDoce('Chocolate');
const romeuJulieta = new PizzaDoce('Romeu e Julieta');
const pizzas = [
  calabresa,
  mussarela,
  calabresa,
  portuguesa,
  aliche,
  frango,
  portuguesa,
  calabresa,
  portuguesa,
  pepperoni,
  quatroQueijos,
  vegetariana,
  chocolate,
  prestigio,
  romeuJulieta,
  prestigio,
  chocolate,
];

No código acima criamos os objetos que trabalharemos, os subjects que serão responsáveis para ouvir tratar os dados, as arrays que guardarão os dados e os objetos de Pizza.

Por fim criamos um array que contem os objetos criados, perceba que alguns dados estão duplicados, pois em um rodízio de pizza um sabor passa mais que uma vez.

Atente-se que não criamos a pessoa1, pois como ela tem algumas peculiaridades veremos duas formas de tratar os dados com os operadores.

pessoa2
.pipe(
  skipWhile(pizza => pizza.type === 'Salgada')
)
.subscribe(
  pizza => pizzasPessoa2.push(pizza)
);

pessoa3
.pipe(
  distinct()
)
.subscribe(
  pizza => pizzasPessoa3.push(pizza)
);

setPizza = (pizza) => {
  pessoa2.next(pizza);
  pessoa3.next(pizza);
}

pizzas.forEach(pizza => setPizza(pizza));

Agora temos as iterações com as duas pessoas que já declaramos como nossos subjects, o método subscribe já foi falado antes em RxJS – Entendendo o conceito na prática, assim como o operador pipe, que foi falado no começo do post.

 

Tanto no subscribe da pessoa2, quando no subscribe da pessoa3 estamos alimentando a array relativa aquela pessoa. O que aparece de diferente agora são os operadores skipWhile e o distinct.

O operador skipWhile é um operador de filtro e ele ignora os valores se a opção fornecida for verdadeira, no nosso caso ele ignorará as pizzas que forem do tipo salgada, pois a pessoa2 só comeria as pizzas doces.

O operador distinct também é um operador de filtro, ele não permitirá que os valores sejam duplicados, sendo assim a pessoa3 que iria comer todas as pizzas não repetindo o sabor, também teve seu problema resolvido.

A função setPizza recebe como parâmetro um objeto pizza e chama os métodos next dos nossos subjects para que os valores sejam iterados.

E por último temos um loop forEach no nosso array de objetos pizzas, que passará para a função setPizza() uma pizza por vez.

Sendo assim matamos dois terços do nosso problema, os da pessoa2 e pessoa3, no entanto ainda não matamos o problema da pessoa1 e podemos resolver de duas formas.

Resolvendo o problema da pessoa1.

A primeira forma é criar dois subjects para a pessoa1, um pessoa1Salgada e pessoa1Doce, criar os pipes para cada uma e alimentar a mesma array, desta forma.

const pessoa1Salgada = new Subject(); 
const pessoa1Doce = new Subject();

// Código omitido
......

pessoa1Salgada
.pipe(
  filter(pizza => pizza.type === 'Salgada' && pizza.name !== 'Mussarela'),
  take(5)
).subscribe(
  pizza => pizzasPessoa1.push(pizza),
);

pessoa1Doce
.pipe(
  filter(pizza => pizza.type === 'Doce'),
  take(3)
).subscribe(
  pizza => pizzasPessoa1.push(pizza),
);

// Código omitido
......

setPizza = (pizza) => {
  pessoa1Salgada.next(pizza);
  pessoa1Doce.next(pizza);
  pessoa2.next(pizza);
  pessoa3.next(pizza);
}

Aqui temos mais dois operadores novos o filter e o take.

O operador filter, não preciso falar que é um operador de filtro, não é mesmo. E ele funciona exatamente igual o filter do JavaScript, ele retorna um resultado se a condição for verdadeira, ou seja, no primeiro caso se o tipo da pizza for salgada e diferente de mussarela e no segundo caso se for doce.

O operador take também é um operador de filtro, entretanto ele é um limitador, por exemplo ele retornará apenas a quantidade de registros que lhe for informado, no primeiro caso 5 e no segundo caso 3.

A segunda forma de fazer é usando o operador merge. E é a que faremos agora.

pizzasSalgadas = (pizza$) => pizza$.pipe(
  filter(pizza => (pizza.type === 'Salgada' && pizza.name !== 'Mussarela')),
  distinct(),
  take(5)
);

pizzasDoces = (pizza$) => pizza$.pipe(
  filter(pizza => pizza.type === 'Doce'),
  take(3)
);

const sourcePizzas$ = from(pizzas);
const salgadas$ = pizzasSalgadas(sourcePizzas$);
const doces$ = pizzasDoces(sourcePizzas$);

salgadas$.pipe(merge(doces$)).subscribe(
  pizza => pizzasPessoa1.push(pizza)
);

Criamos duas funções, pizzasSalgadas() e pizzasDoces() e ambas recebem um observable como parâmetro e retornam um pipe com os filtros já criados.

Os filtros são os mesmo que os anteriores, o que mudou foi apenas um distinct a mais nas salgadas, só para mostrar que podemos enfileirar operadores dentro do pipe como e quantos quisermos.

Após as funções criamos uma variável chamada sourcePizzas$ que recebe como valor o retorno do operador from.

O operador from é um operador de criação e já foi explicado no primeiro exemplo.

O que estamos fazendo é transformando um array de pizzas em um observable.

Depois passando o observable para as funções pizzasSalgadas() e pizzasDoces() guardamos seus retornos as variáveis salgadas$ e doces$, que como recebem um observable se tornam um observable.

E por final a mágica acontece, juntamos os dois observables em um único observable utilizando o operador merge, que é um operador de combinação.

E no final para ver o resultado no nosso console podemos utilizar

console.log(`pizzasPessoa1: ${JSON.stringify(pizzasPessoa1, null, 2)}`);
console.log(`pizzasPessoa2: ${JSON.stringify(pizzasPessoa2, null, 2)}`);
console.log(`pizzasPessoa3: ${JSON.stringify(pizzasPessoa3, null, 2)}`);

Dentro do console.log utilizamos o template literals para exibir os dados e utilizamos também o JSON.stringify que formatará os dados de maneira mais agradável e como estamos mais acostumados.

Nota: Quando declaramos as variáveis com o cifrão($) ou dollar sing, queremos dizer que aquela variável é um observable.

Para rodar os exemplos basta ter o node instalado, navegar até a pasta onde eles estão e digitar:

node operators1
node operators2

E o resultado para o primeiro exemplo será:

Primeiro Valor: Corinthians
Último Valor: Santos

E para o segundo exemplo:

pizzasPessoa1: [
  {
    "name": "Calabresa",
    "type": "Salgada"
  },
  {
    "name": "Portuguesa",
    "type": "Salgada"
  },
  {
    "name": "Aliche",
    "type": "Salgada"
  },
  {
    "name": "Frango",
    "type": "Salgada"
  },
  {
    "name": "Pepperoni",
    "type": "Salgada"
  },
  {
    "name": "Chocolate",
    "type": "Doce"
  },
  {
    "name": "Prestigio",
    "type": "Doce"
  },
  {
    "name": "Romeu e Julieta",
    "type": "Doce"
  }
]
pizzasPessoa2: [
  {
    "name": "Chocolate",
    "type": "Doce"
  },
  {
    "name": "Prestigio",
    "type": "Doce"
  },
  {
    "name": "Romeu e Julieta",
    "type": "Doce"
  },
  {
    "name": "Prestigio",
    "type": "Doce"
  },
  {
    "name": "Chocolate",
    "type": "Doce"
  }
]
pizzasPessoa3: [
  {
    "name": "Calabresa",
    "type": "Salgada"
  },
  {
    "name": "Mussarela",
    "type": "Salgada"
  },
  {
    "name": "Portuguesa",
    "type": "Salgada"
  },
  {
    "name": "Aliche",
    "type": "Salgada"
  },
  {
    "name": "Frango",
    "type": "Salgada"
  },
  {
    "name": "Pepperoni",
    "type": "Salgada"
  },
  {
    "name": "Quatro queijos",
    "type": "Salgada"
  },
  {
    "name": "Vegetariana",
    "type": "Salgada"
  },
  {
    "name": "Chocolate",
    "type": "Doce"
  },
  {
    "name": "Prestigio",
    "type": "Doce"
  },
  {
    "name": "Romeu e Julieta",
    "type": "Doce"
  }
]

O post ficou um pouco extenso, no entanto apenas arranhamos os operadores da biblioteca RxJS. Existem muitos outros e muitas formas de utilizá-los que não foram abordadas aqui, por isso sugiro que procure mais sobre os operadores e bons estudos.

Referências:

https://rxjs-dev.firebaseapp.com/api

https://www.learnrxjs.io/

http://reactivex.io/rxjs/manual/index.html

RxJS – Entendendo o conceito na prática.

Após estudarmos o que é o RxJS neste post: RxJS – Programação Reativa em JavaScript, vamos aplicar o conceito na prática.

Lembrando o problema.

Na nossa situação hipotética tínhamos um site de streaming de vídeo e quando clicássemos nos filtros tínhamos que criar um breadcrumb e manter estas informações, tanto de uma página para outra, quanto se clicássemos em um filme para ver as informações dele e voltássemos para a página de filtros.

Entendendo os conceitos.

Observable.

Em RxJS temos um objeto que se chama Observable, ele emite itens ou envia notificações para seus observadores(observers) chamando os métodos dos observadores.

Subscribe.

Este método é como conectamos um observer(observador) a um Observable. O observador implementa algum subconjunto dos seguintes métodos:

  • onNextUm Observable chama esse método sempre que o Observable emite um item. Este método toma como parâmetro o item emitido pelo Observable.
  • onErrorUm Observable chama esse método para indicar que não conseguiu gerar os dados esperados ou encontrou algum outro erro. Não fará mais chamadas para onNext ou onCompleted. O método onError usa como parâmetro uma indicação do que causou o erro.
  • onCompletedUm Observable chama esse método depois de ter chamado onNext pela última vez, caso não tenha encontrado nenhum erro.

Entendido o conceito acima vamos ao código.

A primeira coisa que devemos fazer é ter o node instalado e fazer download do RxJS

Primeiros Passos com NodeJS.

npm install rxjs

Após instalada a biblioteca vamos criar um arquivo chamado observable.js e digitar o seguinte código:

const { Observable } = require('rxjs');
const breadcrumb = new Array();

const observable = Observable.create(function (observer) {
  observer.next('Filmes');
  observer.next('Aventura');
  observer.next('Espacial');
  observer.next('Star Wars');
  observer.complete();
});

observable.subscribe({
  next: link => breadcrumb.push(link),
  error: err => console.error(`​Mostra se algo der errado: ${err}`),
  complete: () => console.log(breadcrumb.join("->"))
});

Para rodar o exemplo basta entrar na pasta em que você salvou o exemplo e fez download da biblioteca RxJS e utilizar o seguinte comando:

node observable

E será exibido no console:

console

Detalhe a extensão .js não precisa ser digitada.

Perceba que ele formou o breadCrumb inteiro, todos os links que passamos, mas esta não é a forma que ficará no final, fizemos assim apenas para estudar o observable.

Entendendo o código.

Na primeira linha apenas importamos o observable e na segunda linha criamos a variável breadCrumb como um array.

Na terceira linha criamos uma variável observable e atribuímos para o seu valor o observable chamando a função create().

A função create() recebe uma outra função que tem um observer como parâmetro e ele será responsável por chamar os métodos que irão alimentar este observable.

E dentro da função create temos o observer chamando o método do next() quatro vezes, passando os caminhos por parâmetro e por último chamando a função complete, que diz que já terminamos de alterar aquele observer.

Após criarmos e alimentarmos o observable, vamos chamar o subscribe dele.

Como eu disse anteriormente o subscribe vai conectar o observer ao observable. Por isso toda hora que chamamos o observer.next() dentro do observable ele dá um push() no array breadcrumb para salvar o caminho.

A o método error só será chamado se acontecer algum erro no percurso e irá imprimir na tela uma mensagem e o erro.

E o método complete irá imprimir na tela o breadcrumb em si, criando uma string e separando por “->”, através do join(), como vimos na imagem do console.

Ok, criamos o breadcrumb, mas não é exatamente isso que queremos, não é mesmo?

Queremos e precisamos que cada clique em um link guarde o caminho clicado e retorne apenas aquele caminho. E quando navegarmos para outra página e voltarmos para a pesquisa tenhamos o caminho escolhido guardado.

Subject.

Para isso não usaremos o observable e sim o subject, que é um tipo especial de observable, que permite que os valores sejam multicasts para muitos observables. Enquanto os observables puros são unicast (cada observer subscrito possui uma execução independente do observable), os subjects são multicast.

Todo subject é um observable. Internamente o subscribe deste subject não invoca uma nova execução que forneça valores. Ele simplesmente registra o observer fornecido em uma lista de observers, da mesma forma que o addListener() geralmente funciona em outras bibliotecas e linguagens. Ele contém todos os métodos que o observable  contém next(v), error(e) e complete(). Para alimentar um novo valor para o subject, basta chamar next(valor), e ele será enviado para os observers registrados para ouvir o assunto.

Usando o subject para resolver nosso problema.

Agora vamos criar um arquivo chamado breadcrumb.js e digitar o seguinte:

const { Subject } = require('rxjs');
const path = new Subject();
const breadcrumb = new Array();

pushBreadcrumb = link => {

  if (breadcrumb.indexOf(link) !== -1) {
    breadcrumb.splice(breadcrumb.indexOf(link), breadcrumb.length)
  }
  breadcrumb.push(link)
}

path
.subscribe(
  link => pushBreadcrumb(link)
);

click = link => {
  path.next(link);
  console.log(breadcrumb.join("->"));
}

click('Filmes');
click('Aventura');
click('Espacial');
click('Star Wars');

console.log(`---------------`);

click('Aventura');
click('Espacial');

Explicando o código acima temos nas três primeiras linhas a importação do subject, ao invés do observable, criamos um novo subject chamado path e criamos um array com o nome de breadcrumb.

Criamos também uma função chamada pushBreadcrumb, que recebe um parâmetro e testa se este parâmetro já está dentro da array breadcrumb, se sim ele corta a partir do parâmetro até o final a array.

E por quê isso?

Por exemplo a partir do momento que nós navegamos até “Star Wars” e voltamos para “Aventura” afim de ver outros filmes de aventura, ele irá retirar todo o caminho para que o breadcrumb não mostre informações erradas.

E por fim a função é responsável por dar um push() no breadcrumb passando o link que foi recebido como parâmetro.

Abaixo da nossa função temos o path que é nosso subject chamando o subscribe que é o método que conecta o observable.

Este método é igual ao método subscribe do primeiro exemplo, no entanto nós omitimos o error e o complete, por não querer tratá-los.

E o next, recebe um parâmetro chamado link e retorna uma função que é a pushBreadcrumb que falamos acima.

Criamos também a função click(), que será responsável por passar um link para next do observable path e escrever no console o breadcrumb.

No final nós chamamos a função click(), passando cada categoria que clicamos no menu do site.

E o resultado será esse.

breadcrumb

Um detalhe é que simulamos quando estamos em “Star Wars” e clicamos no breadcrumb para voltarmos direto para “Aventura”.

No próximo post vou falar sobre os operadores da biblioteca RxJS e o quão poderosos e funcionais eles são, diminuindo muito o código e ajudando muito na hora de fazer filtros e outras coisas mais que fazemos no dia-a-dia.

RxJS – Programação Reativa em JavaScript

Você já ouviu falar em programação reativa, Observer Pattern, Iterator Pattern e RxJS?

Estava estudando como de resolver um problema de forma simples e objetiva e me deparei com os conceitos de Observer Pattern e programação reativa.

Antes de explicar o que é cada conceito, vamos primeiro entender qual é o problema.

Entendendo o problema.

Vamos imaginar que temos um site de streaming de vídeos e estes vídeos são categorizados por: Filmes, Séries, Documentários.

E cada categoria também tem seus filhos, por exemplo Terror, Comédia, Ação, Romance e Aventura, etc…

E cada filho de cada categoria também, tem seu filho, por exemplo Aventura, tem Western, Heróis, Espacial, etc…

E cada filho do filho de cada categoria também, tem seu filho, por exemplo Espacial temos Star Trek, Star Wars, etc…

Então posso escolher o seguinte filtro: Filme->Aventura->Espacial->Star Wars e escolher o Episódio III e colocar na minha lista de favoritos, para que eu possa assistir mais tarde.

Só que ao navegar na lista de favoritos e voltar eu perco meu filtro, volto para o início da busca e tenho que refazer toda a busca novamente. Vamos supor outra situação, navego para dentro das especificações do filme para ver as informações, ano, atores, resumo e quando volto também perco o filtro.

Como manter este filtro?

Temos diversas formas de gravar estes filtro, mas vamos abordar duas como exemplos, localStorage e gravar no banco.

Tanto um quanto o outro eu preciso, todas as vezes que entrar em uma categoria e no filho dela, pegar os dados, tratar eles e gravar, ou seja, fazer várias requisições para o banco ou gravar várias vezes no localstorage, o que pode onerar um pouco nossa aplicação.

Como resolver este problema de forma mais simples?

Para resolver este problema sem ter que utilizar o localStorage e nem gravar no banco podemos utilizar a biblioteca RxJS que trabalha utilizando o conceito de programação reativa.

O que é RXJS?

RxJS é o acrônimo de Reactive Extensions for JavaScript.

Podemos definir RxJS como:

  • Uma biblioteca javascript que traz o conceito de “programação reativa” para a web, para transformar, compor e consultar fluxos de dados. Desde simples matrizes de valores(Array), a séries de eventos e fluxos complexos de dados.
  • E uma biblioteca para composição de programas assíncronos e baseados em eventos usando sequências observáveis.
  • Fornece um tipo de núcleo, os tipos de satélites do Observer Pattern, (Observable, Schedulers, Subjects) e operadores inspirados em Array tais como, map, filter, reduce, every, etc… Para permitir manipular eventos assíncronos em coleções de dados.

O RxJS combina o padrão Observer com o padrão Iterator e a programação funcional para preencher a necessidade de uma maneira ideal de gerenciar seqüências de eventos.

Observer Pattern.

O padrão Observer oferece um modelo de assinatura no qual os objetos se inscrevem em um evento e são notificados quando o evento ocorre. Esse padrão é a base da programação orientada a eventos, incluindo o JavaScript. O padrão Observer facilita o bom design orientado a objetos e promove um acoplamento flexível.

Quando trabalhamos com JavaScript, acabamos escrevendo muitos manipuladores de eventos, que são funções que serão notificadas quando um determinado evento for disparado. Essas notificações, opcionalmente, recebem um argumento de evento com detalhes sobre o evento.

O paradigma de evento e manipulador de eventos em JavaScript é a manifestação do padrão de design do Observer. Outro nome para o padrão Observer é Pub/Sub, abreviação de Publicação/Assinatura.

Iterator Pattern.

O padrão Iterator permite que os clientes realizem loop de forma efetiva em uma coleção de objetos.

Uma tarefa de programação comum é percorrer e manipular uma coleção de objetos. Essas coleções podem ser armazenadas como uma matriz ou talvez algo mais complexo, como uma estrutura de árvore ou gráfico. Além disso, podemos precisar acessar os itens na coleção em uma determinada ordem.

O padrão Iterator resolve esse problema separando a coleção de objetos da passagem desses objetos implementando um iterador especializado.

Muitas linguagens possuem Iterators embutidos suportando construções do tipo ‘for-each’ e interfaces IEnumerable e IEnumerator. No entanto, o JavaScript suporta apenas loop básico na forma de instruções for, for-in, while e do while.

O padrão Iterator permite que os desenvolvedores de JavaScript projetem construções de looping que sejam muito mais flexíveis e sofisticadas.

Programação reativa.

A programação reativa é apenas uma maneira diferente de criar aplicativos de software. Essencialmente, seu software é construído para “reagir” às mudanças que acontecem (como eventos de cliques, dados sendo buscados, etc) ao invés da maneira típica de escrever software onde explicitamente escrevemos código (também conhecido como programação “imperativa”) para lidar com essas mudanças.

Programação reativa é programar com fluxos de dados assíncronos, ou seja, que não se realizam ao mesmo tempo ou no mesmo ritmo de desenvolvimento em relação a outros fluxos ou eventos.

Sua importância é devida ao crescimento da internet e a demanda de aplicativos e operações em tempo real, os deixando mais dinâmicos. Para isso ela é baseada em quatro pilares.

  • Responsivo: As aplicações  precisam responder o mais rápido possível ao usuário, simplificam os tratamentos de erros e os tratam com rapidez e eficácia.
  • Resiliente: As aplicações precisam ser resistentes as falhas, um erro não pode travar o sistema todo, mesmo se uma falha aconteça em um módulo ou serviço o restante da aplicação precisa funcionar e esse erro tem que ser corrigido o mais rápido possível.
  • Elástico: A aplicação tem que ser escalável, ou seja, suportar vários acessos e usuários sem comprometer sua performance. Precisam aumentar ou diminuir os recursos de hardware quando necessário.
  • Orientado a mensagens: As aplicações devem ser assíncronas, passando mensagens de um componente para outro para estabelecer fronteiras entre os componentes e garantir baixo acoplamento, isolamento, transparência na localização e provêem meios para delegar o tratamento de erros através de mensagens.

Mais sobre programação reativa pode ser visto em O Manifesto Reativo.

Conceitos da RxJS.

Visto todas estas informações acima vamos falar sobre os conceitos da biblioteca em si. Estes conceitos essenciais resolvem o gerenciamento de eventos assíncronos e são:

  • Observable: representa a ideia de uma coleção invocável de valores ou eventos futuros.
  • Observer: é uma coleção de retornos de chamada que sabe como escutar os valores entregues pelo Observable.
  • Subscription: representa a execução de um Observable, é principalmente útil para cancelar a execução.
  • Operators: são funções puras que permitem um estilo de programação funcional de lidar com coleções com operações como map, filter, concat, reduce, etc.
  • Subject: é o equivalente a um EventEmitter e a única maneira de transmitir um valor ou um evento para vários Observadores.
  • Schedulers: são despachantes centralizados para controlar a simultaneidade, permitindo-nos coordenar quando o cálculo ocorre em, e. setTimeout ou requestAnimationFrame ou outros.

Resolvendo nosso problema.

Para resolver nosso problema de forma simples sem precisar fazer as requisições no banco e nem precisar gravar e buscar toda hora no localStorage, podemos um observable que será alimentado toda vez que o usuário escolher um filtro e será lido toda vez que o usuário voltar para a página de lista de filmes, poupando a aplicação de fazer requisições desnecessárias.

A implementação do exemplo ficará para o próximo post, para ser detalhada passo a passo.

Referências:

Site Oficial do RxJS

Observable Pattern

Iterator Pattern

https://martinfowler.com/articles/collection-pipeline/#NestedOperatorExpressions

https://thinkster.io/tutorials/learn-rxjs-observables/what-is-rxjs

O Manifesto Reativo

TypeScript – Interface e Class

Em orientação à objeto, classe e interface são estruturas que ajudam na construção de um objeto.

Uma interface é um conjunto de métodos e propriedades que descrevem um objeto, porém não inicializa nem os implementa.

Uma classe é uma estrutura ou plano, que a partir dela podemos criar objetos que compartilham uma mesma configuração, propriedades e métodos.

Como vimos nos posts anteriores, TypeScritpt – Primeiros passos e TypeScript – Tipos de dados, diferentemente do JavaScript o TypeScript é tipado e orientado à objeto e por isso a implementação de classe e interface é bem comum.

Interface.

Entenda a interface como um contrato de um objeto, ela que define quais os métodos ou propriedades um objeto terá, quais serão obrigatórias, quais serão opcionais, quais poderão ser alteradas e quais serão apenas de leitura

Exemplo:

interface Carro {  
  readonly motor: string;
  readonly portas: number;
  combustivel: string;
  cor?: string;
  airBag?: boolean;
}

let omega: Carro = {
  motor: "4.1", 
  portas: 2, 
  combustivel: "Gasolina"
}

omega.cor = "preta";
omega.combustivel = "Gás";

/**
 * A IDE de desenvolvimento apontará um erro,
 * pois motor é readonly
 */
//omega.motor = "3.0";
console.log(omega);

No exemplo acima declaramos uma interface chamada “Carro“, perceba que ela tem cinco propriedades, “motor“, “portas“, “combustivel“, “cor” e “airBag“.

As propriedades motor, portas e combustivel são propriedades obrigatórias na implementação da nossa interface. Só que motor e porta são readonly, ou seja, após implementadas estas propriedades não podem ser alteradas.

cor e airBag são propriedades que são opcionais(podem ou não serem implementadas). E isso fica explícito quando usamos o ponto de interrogação(?) antes de tipar a variável. Todas as variáveis que tem o ponto de interrogação(?) são variáveis opcionais.

Readonly ou const?

Uma dúvida frequente é quando usar readonly e quando usar const(para saber mais de const acesse: Var, Let e Const em JavaScript).

Segundo a própria documentação do TypeScript:

A maneira mais fácil de lembrar se você deve usar readonly ou const é perguntar se você está usando uma variável ou uma propriedade. As variáveis usam const, enquanto as propriedades usam readonly.”

Classes.

Entenda a classe como a estrutura de um objeto, por exemplo temos uma classe animal e um objeto cachorro que herda as características do objeto animal, também temos uma classe gato que também herda as características de animal, só que tem suas peculiaridades, assim como o cachorro.

Exemplo:

class Animal {
  name: string;
    constructor(name: string) { 
      this.name = name; 
    }
    move(distance: number = 0) {
      console.log(`${this.name} se move por ${distance}m.`);
    }
}

class Dog extends Animal {
  constructor(name: string) { 
    super(name); 
  }
  move(distance = 15) {
    console.log("Corre...");
    super.move(distance);
  }
}

let buddy = new Dog("Buddy");

O exemplo acima exemplifica o que foi dito, criamos a classe animal, e a classe cachorro(Dog), herda as características do animal, poderíamos implementar as peculiaridades do cachorro na própria classe, mas ainda sim ele herdarias as características do animal.

Modificadores:

As classes tem modificadores em suas propriedades que definem o nível de acesso que cada uma terá. E são eles:

  • public;
  • private;
  • protected.

Public: É o modificador padrão, toda a variável que for declarada sem um modificador de acesso automaticamente se torna pública.

Private: Quando utilizamos o modificador private em uma variável, esta não pode ser acessada fora da classe que a contém.

Protected: O modificador protected é bem parecido com o private, mas se difere porque uma classe que herda de outra pode acessar as variáveis com este modificador.

Assessores:

Quando temos uma propriedade private, podemos acessa-la através dos Getters e Setters, isso dá ao TypeScript uma maneira mais refinada de ter um controle sobre a propriedade do objeto, como Java e C#.

Para exemplificar os conceitos acima vamos implementa-los em um exemplo:

class Person {
  public name: string;
  private _age: number;
  protected height: number;

  public get age() : number {
    return this._age;
  }

  public set age(v : number) {
    this._age = v;
  }
}

class Employee extends Person{
  setHeight(height: number){
    this.height = height;
  }
}

let employee = new Employee();

employee.name = "Bognar";
employee.age = 35;
employee.setHeight(1.84);

//Indicará erro
//employee._age = 35;
//employee.height = 1.84;

console.log(employee)

Note que a classe Person tem os três modificadores de acesso que falei anteriormente.

Na propriedade name o modificador é o public, por isso que employee.name não dá erro quando atribuímos o valor “Bognar” para ela.

A propriedade _age é privada, perceba que ela começa com um underscore( _ ) para diferenciar dos métodos get() e set() que também chamam age.

O get() e o set() da propriedade conseguimos acessar, por isso que quando atribuímos employee.age não dá erro, pois não acessamos diretamente a propriedade _age e sim seu set().

A propriedade height de Person é declarada como protected, por isso não conseguimos acessar ela diretamente em employee. Mas podemos acessar ela na classe Employee e assim criar um método que a torna visível fora da classe, setHeight() e ai sim conseguimos atribuir um valor para ela.

Se tentarmos acessar employee._age ou employee.height direto, a IDE de desenvolvimento, no meu caso o Visual Studio Code, indicará um erro, falando que as propriedades não são acessíveis.

erroClass

Referências:

https://www.typescriptlang.org/index.html

https://pt.wikipedia.org/wiki/Interface_(programa%C3%A7%C3%A3o_orientada_a_objetos)

https://pt.wikipedia.org/wiki/Classe_(programa%C3%A7%C3%A3o)

TypeScript – Tipos de dados

Uma das maiores diferenças do TypeScript para o JavaScript é a tipagem de suas variáveis. Em JavaScript podemos atribuir um valor numérico para uma variável e logo depois mudar este valor para booleano, para uma string, um array ou mesmo um objeto e tudo estará ok.

Veja o exemplo abaixo:

let qualquer = 1;
console.log(qualquer, typeof qualquer );

qualquer = 'String';
console.log(qualquer, typeof qualquer );

qualquer = true;
console.log(qualquer, typeof qualquer );

qualquer = [1, 2, 3, 4, 'String', true, 5, 6, 'STRING', false];
console.log(qualquer, typeof qualquer );

qualquer = {
  name: 'Bognar',
  date: new Date(),
  article: 'TypeScript',
  publish: true
};

console.log(qualquer, typeof qualquer );

Já no TypeScript temos os tipos bem definidos e são eles:

  • String
  • Boolean
  • Number
  • Array
  • Tuple
  • Enum
  • Any
  • Void

Tipos básicos

String

String é um tipo básico e fundamental no JavaScript tanto para construção aplicativos web e mobile quanto para a construção de programas no lado do servidor. Como em outras linguagens, usamos o tipo string para nos referirmos a tipos de dados textuais. Assim como o JavaScript, o TypeScript também usa aspas duplas (“) ou aspas simples (‘) para envolver os dados da string.

Podemos definir uma variável string da seguinte forma:

let text: string = 'Valor da string';
text = 'Mudei o valor';

Se tentarmos alterar o valor de text para um número por exemplo 3 o depurador do Visual Studio Code indicará o seguinte erro:

errostring

E a linha que estamos alterando também indicará erro.

Number

No TypeScript assim como no JavaScript, todos os números são valores de ponto flutuante e recebem o tipo number. Além dos literais hexadecimais e decimais, o TypeScript também suporta literais binários e octal introduzidos no ECMAScript 2015.

let num: number;
num = 4;
num = 5 + 8;

let anotherNum: number = 5.8;
let hexNum: number = 0xf00d;
let binaryNum: number = 0b1010;
let octalNum: number = 0o744;

Boolean

Sem dúvidas é o tipo mais básico de dados que tanto o JavaScript quando o TypeScript tem, ele recebe apenas o valor true/false.

let isValid: boolean = true;
isValid = false;

Tipos complexos

Fora estes tipos básicos temos também o array, tupla(tuple) e enum.

Array

O array é um tipo muito utilizado em JavaScript. E em TypeSript podemos declará-la de duas maneiras.

A primeira é utilizando o tipo do elemento seguido por [] (colchetes).

let arr: string[] = ['Arroz', 'Feijão', 'Couve', 'Bisteca de Porco'];

A segunda é utilizando o tipo Array genérico.

let arrGeneric: Array<string> = ['Arroz', 'Feijão', 'Couve', 'Bisteca de Porco'];

Tuple(Tupla)

Os tipos de tupla permitem que você expresse um array onde o tipo e um número fixo de elementos é conhecido, mas não precisa ser o mesmo.

let tuple: [string, number, string, number];
tuple = ['hello', 1, 'world', 2];

console.log(tuple[0]);
console.log(tuple[1]);

No exemplo acima temos um número definido de elementos na array, 4 e ele são duas strings e dois números

Se definirmos a tupla alterando as ordens que os tipos foram de declarados mais uma vez o Visual Studio indicará um erro;

tuple = [1, 'hello', 2, 'world'];

erroTupla

Enum

Enum é um tipo de dados que não existe no JavaScript mas foi adicionado ao TypScript com o intuito de fornecer nomes mais amigáveis a conjuntos de valores numéricos. Enums são muito comuns em linguagens como Java e C#.

enum Color {Red, Green, Blue, Yellow};
enum AnotherColor {Red = 1, Green = 2, Blue = 4, Yellow};

Se imprimirmos o enum Color, veremos que os valores de Red será 0, Green será 1, Blue 2 e Yellow será 3.

Assim como se imprimirmos o enum AnotherColor, Red será 1, Green 2, Blue 4 e Yellow que não foi atribuído valor será 5.

Tipos especiais

Temos também outros dois tipos de dados o any e o void.

Any

Any é um tipo de dados muito utilizado para quem está migrando do JavaScript para o TypeScript ou quem está recebendo os dados de uma outra biblioteca e não sabe seu valor.

E ele literalmente quer dizer qualquer um. Então declarando uma variável como o tipo any podemos atribuir qualquer valor para ela.

let qualquer: any;
qualquer = 'String';
qualquer = 4;
qualquer = true;

Void

O tipo void é muito usado junto com funções, serve para dizer que o valor é vazio, não é atribuído nada.

function print(msg: string ): void {
  console.log(`Função sem retorno: ${msg}`);
}

print('Escreve algo na tela');

Obs: Declarar variáveis do tipo void não é útil porque você só pode atribuir undefined ou null a elas.

 

TypeScript – Primeiros passos

JavaScript é sem dúvidas uma das linguagens de programação mais utilizadas no mundo, tudo por causa dos seus recursos e da sua grande flexibilidade.

Podemos programar client-side, server-side, mobile, games, etc. Tudo isso usando apenas o JavaScript.

A linguagem é fácil, simples e de rápida aprendizagem, mas contém um problema que se agrava quando desenvolvemos aplicações complexas e robustas.

Diferente de outras linguagens como Java, C# e outras fortemente tipadas, JavaScript não possui tipos, classes e aquela velha e famosa orientação a objetos que tanto vimos no segundo, terceiro e quartos semestres da faculdade, mesmo com a implementação do ES6, tudo é transpilado para JavaScript puro.

ES6:

class Veiculo {
    constructor(ano, modelo, cor) {
        this.ano = ano;
        this.modelo = modelo;
        this.cor = cor;
    }
}

JavaScript puro:

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Veiculo = function Veiculo(ano, modelo, cor) {
  _classCallCheck(this, Veiculo);

  this.ano = ano;
  this.modelo = modelo;
  this.cor = cor;
};

Outro problema também são os programadores que migram de linguagem fortemente tipada para o JavaScript sentem uma dificuldade de adaptação.

Pensando nisso um engenheiro da Microsoft e sua equipe de desenvolvimento resolveram criar o TypeScript.

Este engenheiro não é ninguém menos que Anders Hejlsberg, que esteve envolvido na criação e no desenvolvimento do Turbo Pascal e do Delphi quando trabalhava para a Borland. E depois foi um dos desenvolvedores do C# e da plataforma .Net na Microsoft

Ok, mas o que é o TypeScript?

TypeScript é um superconjunto de JavaScript desenvolvido pela Microsoft que adiciona tipagem e alguns outros recursos a linguagem.

O TypeScript é projetado para o desenvolvimento de grandes aplicativos e transpilado para JavaScript. Como o TypeScript é um superconjunto de JavaScript, os programas JavaScript existentes também são programas TypeScript válidos.

O TypeScript pode ser usado para desenvolver aplicativos JavaScript que executam tanto do lado do cliente quanto do lado do servidor(Node.js).

O TypeScript suporta arquivos de definição que podem conter informações de tipo de bibliotecas JavaScript existentes, assim como os arquivos de cabeçalho C ++ podem descrever a estrutura dos arquivos de objetos existentes. Isso permite que outros programas usem os valores definidos nos arquivos como se fossem entidades TypeScript digitadas estaticamente.

Existem pacotes de terceiros para bibliotecas populares, como jQuery, MongoDB e D3.js. Pacotes TypeScript para os módulos básicos do Node.js também estão disponíveis, permitindo o desenvolvimento de programas Node.js dentro do TypeScript.

Instalando o TypeScript.

Para instalar o TypeScritp é fácil, basta ter o node instalado no seu computador e instalar com o npm globalmente.

npm install -g typescript

Após instalado vamos criar o primeiro código utilizando TypeScript.

Criando um código com TypeScript.

Como sempre devido a “Maldição do Hello World” vamos criar nosso primeiro código imprimindo no console o Hello World. Mas primeiro vamos criar uma estrutura de pastas que será utilizada para todos os nossos exemplos.

TypeScript |
           |-> src |
                   |-> HelloWorld |
                                  |-> HelloWorld.ts

Vamos criar uma pasta TypeScript e dentro dela uma pasta src, dentro desta pasta src outra pasta que será o nome do exemplo que criaremos e dentro dela finalmente o arquivo .ts

Esta estrutura é necessária, pois iremos configurar o Visual Studio Code para transpilar o código TypeScript para JavaScript automaticamente.

HelloWorld.ts

const saudacao: string = 'Hello World!';

console.log(saudacao);

Acima é um exemplo de uma constante saudação declarada como um tipo string e atribuída o valor de ‘Hello World!’, depois seu valor é exibido no console.

Para transformarmos este código em JavaScript precisamos utilizar o seguinte comando:

tsc HelloWorld.ts

E isso nos gerará um código assim:

var saudacao = 'Hello World!';

console.log(saudacao);

Porém cada vez que alterarmos o código precisaremos rodar o comando novamente, isso pode e provavelmente irá nos causar dor de cabeça. Mas para que isso não aconteça vamos configurar o Visual Studio Code fazendo que este processo seja automático.

Criando o tsconfig.json

Dentro da pasta TypeScript e fora da pasta src crie um arquivo chamado tsconfig.json e nele digite:

{
  //Opções de compilação
  "compilerOptions": {
    //Qual a versão do ecmascript será compilada
    "target": "es5",
    //Geração de módulo padrão
    "module": "commonjs",
    //Criará um source map
    "sourceMap": true,
    //Salvar e gerar automaticamente o arquivo javascript
    "watch": true
  },
  //Quais pastas serão transpiladas
  "include": [
    "src/**/*"
  ]
}

Este arquivo será responsável por compilar o TypeScript para JavaScript e também toda e qualquer alteração que for feita no arquivo TypeScript ele automaticamente recompilará.

Feito isso temos que configurar o Visual Studio Code para que ele rode o processo. Então vá em :

Visualizar -> Paleta de comando -> Executar tarefa de compilação -> TypScript\tsconfig.json

E pronto agora toda vez que você alterar o arquivo.ts o arquivo.js será atualizado e um arquivo.js.map será criado.

Quando e onde utilizar o TypeScript?

Podemos utilizar o TypeScript quando quisermos uma maior segurança nas nossas aplicações, quando precisarmos que elas sejam fortemente tipadas, com sólidos conceitos de orientação à objeto e quando tivermos programadores de outras linguagens como C# e Java se aventurando pelo JavaScript.

Várias bibliotecas e frameworks já utilizam TypeScript ou dão suporte a ele como :

  • React
  • React Native
  • Angular
  • Vue
  • Node
  • Knockout
  • Dojo 2
  • Glimmer
  • WebChat
  • ASP.NET core

Este artigo foi mais para conhecermos o TypeScript e sua configuração inicial para que possamos nos próximos colocar a mão na massa e conhecer tudo o que ele pode nos oferecer.

Referências e links:

Site oficial do TypeScript

Wikipedia TypeScript

Wikipedia Anders Hejlsberg

Twitter.com @typescriptlang

GitHub Microsoft/TypeScript

 

React – Componentes de Classe e Funcionais

Como vimos nos posts anteriores, React – Primeiros Passos e React – Criando o primeiro componente, react é uma biblioteca que controla os componentes da nossa aplicação web e estes componentes podem ser divididos da seguinte forma:

  • Componentes de classe
  • Componentes funcionais

Componentes de classe

Os componentes de classe na verdade não são específicos do react, eles são uma implementação que surgiu no ES6.

Classe nada mais é que uma função especial na qual você pode definir utilizando a palavra reservada class.

Um componente de classe no react sempre extende o Component, da biblioteca.

Vamos entender melhor criando um exemplo.

Para criarmos um componente vamos utilizar o create-react-app.

create-react-app blog-component

Caso não tenha instalado leia este post.

Depois de criado o projeto, basta navegar até ele.

cd blog-component

Dentro da pasta iniciar o projeto.

npm start

Ou se tiver com o yarn instalado utilizar o comando

yarn start

localhost-react

Podemos apagar tudo dentro da pasta src, menos o arquivo index.js e vamos criar uma pasta components dentro da pasta src e um arquivo App.js dentro da pasta components.

Temos também que alterar o index.js para que ele não mais utilize as referências dos arquivos que apagamos.

O arquivo index.js ficará assim:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

ReactDOM.render(<App />, document.getElementById('root'));

Agora faremos no nosso componente App.js um componente de classe.

 

import React, { Component } from 'react'
export default class App extends Component {
  render() {
    return (
      <div>
        <h1>Hello Word!</h1>
      </div>
    )
  }
}

Pronto, como declaramos nosso componente como classe já o torna um certo?

Errado.

Uma das coisas que o site do react diz é que um componente de classe só será utilizado quando este componente precisar controlar o estado, senão poderemos utilizar um componente funcional.

Componente Funcional.

Os componentes funcionais são literalmente funções javaScript, eles recebem um único argumento de objeto “props” e retornam um elemento react válido.

Este elementos são chamados de componente ou elementos burros, pois eles não tratam o state.

Geralmente utilizamos estes elementos para, mostrar dados, mostrar imagens, criar listas, aplicar estilos entre outros.

Em contrapartida utilizamos o componente de classe quando precisamos buscar algo em uma api, temos que controlar o estado deste componente, quando chamamos outros componentes e em casos que precisamos de algo mais complexo.

Um componente funcional seria mais ou menos assim.

Vamos criar um componente chamado Title.js na pasta componets. E vamos digitar o seguinte código.

import React from 'react';
export default (props) => {
  return (
    <div>
      <h1>{props.title}</h1>
    </div>
  )
}

Como iremos apenas exibir um título neste componente não necessariamente precisa ser um componente de classe, pois não controla nenhum estado, apenas recebe uma propriedade e a exibe ela na tela.

 

Basta importar no App.js e colocar no lugar da tag h1 que utilizávamos para exibir a mensagem na tela.

import React, { Component } from 'react';
import Title from './Title';

export default class App extends Component {
  render() {
    return (
      <div>
        <Title title='Hello World'/>
      </div>
    )
  }
}

E então passamos como parâmetro o title, que será o mesmo exibido em props.title.

Um exemplo mais completo.

Imagine que você tenha uma lista e dentro desta lista você precise aplicar um estilo para cada elemento desta lista, você pode usar um componente de função chamando outro componente de função, pois você não irá alterar o estado em nenhum deles.

Primeiro vamos alterar o App.js para que ele receba uma lista no state contendo vários cursos.

Depois vamos importar um componente que iremos criar chamado CoursesList.js.

import React, { Component } from 'react';
import Title from './Title';
import CoursesList from './CoursesList';

export default class App extends Component {
    state = {
        courses: [
            "React", 
            "React Native",
            "JavaScript",
            "Node"
        ]
    }
    render() {
        return (
            <div>
                <Title title='Hello World'/>
                <CoursesList list={this.state.courses}/>
            </div>
        )
    }
}

Abaixo do componente Title que já estava no nosso código, passamos o componente CoursesList que irá receber um parâmetro list com o valor de this.state.courses.

CoursesList.js

import React from 'react';
import Course from './Course';

export default (props) => {
  return (
    <div>
      {props.list.map(course => <Course title={course}/>)}
    </div>
  )
}

O componente CoursesList, embora vá chamar outro componente ele não precisa ser um componente de classe, pois ele não tem um estado para manipular, ele apenas faz um map() em uma lista que ele recebeu via propriedade(props) e passa para o componente Course através da propriedade title estes dados para serem tratados.

Course.js

import React from 'react';

export default (props) => {
  return (
    <div>
      <p style={{ color: 'red' }}>{props.title}</p>
    </div>
  )
}

Por fim o componente Course.js, este componente também é um “componente burro” ou funcional.

Ele é mais um componente que não trata o estado, apenas recebe um parâmetro, aplica um estilo, definindo a cor vermelha para os cursos e mostra na tela.

Referências

https://reactjs.org/docs/components-and-props.html

Redux – Controlando o estado global da sua aplicação.

Quando falamos em ecossistema react, não podemos esquecer do redux, que é um outro framework muito utilizado em conjunto com ele.

O que é o redux?

Para definirmos o que é o redux, temos que antes ter em mente o que é o react, veja em: React – Primeiros Passos, mas para simplificar, react é uma biblioteca que controla os componentes da sua aplicação.

Como o react controla os componentes da sua aplicação o redux controla o estado global da sua aplicação.

Então, redux é um framework de gerenciamento de estado(controle de um estado único na sua aplicação).

O react não faz isso?

A resposta é não. O react tem uma propriedade chamada state, mas este state é apenas do seu componente, você consegue passar este valor para seus filhos através das propriedades, mas receber de volta é uma coisa complicada e passar para o pai deste componente é mais complicado ainda.

Vamos pensar assim, uma aplicação é um conjunto de componentes, uma árvore. E nesta árvore temos várias ramificações.

Cada ramificação é um componente que chama outro componente, que chama outro componente, que chama outro componente, etc..

Imagina você alterando um estado em um componente que foi filho, do filho, do filho do filho do componente A, o componente A4, digamos agora que precisa pegar estas informações no componente C12, imagina o trabalho para pegar isso?

Uma imagem vale mais que mil palavras.

O que eu falei anteriormente pode ser visto e entendido melhor nesta imagem.

Wthout-redux-with-redux

Na primeira árvore temos um exemplo de componentes sem o redux. Perceba que eles conversam apenas com os mais próximos, não conseguem conversar com os que estão mais distantes e isso dificulta e muito o desenvolvimento da nossa aplicação.

Já com redux temos a store, que é a única fonte de verdade da sua aplicação, um estado único para a aplicação, não mais um estado para cada componente.

Tríade do redux.

Um conjunto de princípios compõem o que é o conceito do redux e são eles:

Store:

  • É a única fonte de verdade da sua aplicação.
  • Um estado único para a aplicação, não mais um estado para cada componente.

Action:

  • Um componente dispara uma ação(dispatch) e esta ação gera uma mudança no estado.
  • Todos os componentes que estão registrados neste estado serão renderizados. 
  • Não altera o estado, evolui o estado.
  • O estado é dividido em pequenas partes, as ações alterarão cada pequena parte deste estado, os componentes que estiverem registrados nesta parte sofrerão esta modificação. 
  • Dependendo de onde você estiver na sua aplicação cada parte do estado terá valores diferentes, porém o estado ainda será um objeto único.

Reducer: 

  • São  funções puras que evoluem o estado.
  • Transmitem as alterações emitidas pelas actions e aplicam na store.

Exemplo:

Para entendermos o redux vamos fazer um contador, bem simples, algo fácil de entender.

Como disse anteriormente o redux não é exclusivo do react e para utilizar ele precisamos adicionar um pacote de ligação, o react-redux.

Então utilizaremos os seguintes pacotes npm:

  • react
  • redux
  • react-redux

Passos para a criação:

Você precisará ter o create-react-app instalado, caso não tenha leia:

React – Primeiros Passos

React – Criando o primeiro componente

create-react-app contador-redux

Após o projeto criado navegue até a pasta.

cd contador-redux

Dentro dela inicie o projeto.

npm start

Dentro da pasta src, vamos deletar tudo e criar um index.js do zero. Também vamos criar 3 pastas para separarmos os arquivos indicando o que cada um fará.

Vamos criar então as pastas actions, components e reducers, lembrando, dentro da pasta src.

count-redux

Criaremos dentro da pasta action o arquivo counterAction.js, dentro da pasta reducers o arquivo counterReducer.js e dentro da pasta components o arquivo counter.js

Geralmente criaríamos tudo como counter, mas para ficar mais fácil o entendimento alterei os nomes para adicionar o que cada arquivo é encarregado de fazer.

counter-redux2

Entendendo para fazer.

Vamos fazer um contador, então temos que entender quais as ações que ele tomará.

Temos 3 ações possíveis, incrementar, decrementar e aumentar o “step” do contador, de quanto em quanto ele irá aumentar.

Ótimo, já definimos o que nossas ações farão, então bora programar.

Dentro do arquivo counterActions.js vamos digitar o seguinte código:

action

Não poderia ser mais simples, não é mesmo?

O que estamos falando acima é que, quando chamar a função increment() retornaremos um tipo ‘INCREMENT’.

Quando chamarmos a função decrement() retornaremos um tipo ‘DECREMENT’

E quando chamarmos a função stepChanged(), recebendo como parâmetro e retornaremos um tipo ‘STEP_CHANGED’ e também um payload com o valor recebido deste e.

Ficou difícil de entender?

Imagine assim o action recebe uma chamada, de incrementar o valor e ele passa para o reducer o que precisa fazer, através do tipo ‘INCREMENT’.

No arquivo counterReducer.js vamos digitar o seguinte código.

reducer

Pode parecer estranho no começo, mas depois o entendimento fica mais fácil.

O que fizemos foi criar um estado inicial para o contador, com seu valor (number) começando com 0 (zero) e o step começando com 1 (um).

Logo após iniciar o estado retornamos uma função que recebe um estado e uma ação(state = INITIAL_STATE, action) . 

Dentro desta função testamos qual o tipo da ação foi enviado e retornamos o estado atualizado para a store.

Ficou claro ou ainda ficou confuso?

Vamos pensar assim, o action disparou para o reducer uma ação do tipo ‘INCREMENT’.

O reducer ouviu esta ação e pegou o estado, viu quanto ele tinha que atualizar, (step) (um), e quanto o valia o contador, (number) 0 (zero).

Feito isso ele vai criar um novo estado a partir do estado atual e retornar o valor atualizado para a store, step 1 (um), number 1 (um).

O fluxo do redux seria assim, o componente dispara uma ação, esta ação passa para o reducer qual parte precisa ser alterada da store, o reducer altera esta parte e devolve um novo estado para store e ela por sua vez atualiza o componente.

ReduxFlow

Criando e conectando com o redux

Até agora não criamos nenhum componente react, vamos criar o que vai controlar e disparar as ações.

Dentro da pasta components vamos criar o componente counter.js

counterjs

Agora as coisas ficarão um pouco mais complicadas, mas bem explicadas conseguiremos entender facilmente.

Como disse não podemos utilizar somente o redux com o react sem um outro pacote de ligação. Por isso chamaremos o react-redux

Do redux importamos o bindActionCreators(), que ligará as ações criadas com o dispatchE é só isso mesmo.

Mas como assim?

Calma jovem Padawan, a força está com você, não retire os cabelos.

Eu não disse que o estado será mudado pelas actions? Então, o que estamos fazendo é apenas mapeando as ações e criando o gatilho para elas, você entenderá depois.

E do react-redux estamos importando o connect(), que juntará tudo, o redux com o react.

Como nosso componente não terá que controlar estado, podemos criar um componente funcional, veremos mais sobre isso em um próximo post.

const Count = props => ()

O props será um atributo mapeado pelo redux agora. Nele estarão nossas ações e o nosso estado.

<h1>Contador: {props.counter.number}</h1>

Acima um exemplo de estado: o counter é um atributo do nosso estado global

<button onClick={props.increment}> Incrementar </button>

<button onClick={props.decrement}> Decrementar </button>

Agora um exemplo de action: increment() e decrement(), são actions mapeadas da nossa aplicação.

Mas tudo isso é possível graças a duas funções, mapStateToPros() e mapDispatchToProps().

Na verdade estas ações poderiam ter qualquer nome, mas os criadores do react-redux, indicam colocar estes nomes para que seja mais fácil entender o que as funções fazem e para uma melhor semântica.

mapStateToProps.

A função mapStateToProps() recebe como parâmetro o state global e para cada atributo do state que queremos mapear criaremos um atributo no props, por exemplo:

const mapStateToProps = state => ({counter: state.counter});

Quero que meu props tenha o atributo counter e que pegue este valor de state.counter

Este é um padrão de projeto conhecido como decorator. Ele recebe um componente e retorna o mesmo componente, só que agora decorado, adicionado de novas funcionalidades.

mapDispatchToProps.

A função mapDispatchToProps() recebe como parâmetro o dispatch e retorna o bindActionCreator() que recebe dois parâmetros. O primeiro será um objeto com todas as actions que queremos utilizar e o segundo será o próprio dispatch, que será responsável por disparar todas as ações que foram mapeadas.

const mapDispatchToProps = dispatch => bindActionCreators({ increment, decrement, stepChanged} , dispatch);

Mas tudo isso não faz sentido algum se não ligarmos as funções.

E para isso utilizamos o connect().

export default connect(mapStateToProps, mapDispatchToProps)(Counter)

Estamos conectando ao nosso componente Counter, as propriedades do estado mapeadas e as actions também mapeadas.

Criando a Store

Feito tudo isso temos que criar a store e atribuir o state nela, para isso vamos utilizar o index.js.

 

store

No index.js importamos tudo que iremos utilizar, seja do react, redux, react-redux ou componentes e reducers que criamos.

const reducers = combineReducers({
    counter: counterReducer
})

No código acima estamos criando uma variável reducers, que no nosso caso terá apenas um reducer, o combineReducers(), serve para unir todos os reducers que iremos utilizar na aplicação.

Estamos dizendo que dentro da nossa variável reducers teremos um atributo chamado counter e este atributo receberá o valor de counterReducer, ou seja, todo atributo que for alterado dentro do counterReducer o estado no atributo counter será evoluído.

O createStore() literalmente cria a store, passamos como parâmetro a variável reducers, que já foi tratada anteriormente.

O Provider, que pega o estado e passa para os componentes internos da aplicação.

A aplicação inteira é envolvida pelo provider e tudo que está envolto por ele passa a ser seu filho.

Como o próprio criado do redux Dan Abramov, GitHub, Twitter, Medium diz, você nem sempre precisará do redux para programar em react ou react-native, o nosso exemplo é bem básico e apenas para estudo, apenas para conhecer o funcionamento do redux com react.

Em aplicações simples assim utilizar o redux pode complicar mais ainda a sua vida.

O fato é que, quando precisamos controlar o estado global da nossa aplicação que tenha muitos componente, faça requisições para apis e tenha inúmeras funcionalidades, o redux é uma mão na roda.

Porém pode se tornar um monstro de 7 cabeças se não for bem implementado.

Referências:

https://reactjs.org

https://redux.js.org/

https://github.com/reduxjs/react-redux

https://redux.js.org/basics/usagewithreact

View story at Medium.com

View story at Medium.com

React – Ciclo de vida de um componente

Já vimos anteriormente que o React utiliza componentes para criar a View do seu projeto, certo?

Leia mais em:

React – Primeiros Passos;

React – Criando o primeiro componente;

React – Configurando rotas com react-router.

No entanto esta View tem fases, que chamamos de ciclos de vida. Estes ciclos de vida são divididos em 3 partes:

  • Montagem
  • Atualização
  • Desmontagem

Cada parte é composta por vários métodos, que são:

Montagem:

  • constructor()
  • render()
  • componentDidMount()

Atualização:

  • render()
  • componentDidUpdate()

Desmontagem:

  • componentWillUnmount()

Os métodos listados acima são considerados os métodos principais do ciclo de vida do componente React, no entanto existem outros que explicarei mais tarde.

constructor()

Este método é um dos métodos principais do ciclo de vida do React, mas não é necessariamente obrigatória a sua implementação.

Utilizamos o constructor() quando precisamos inicializar o state de um componente.

  • O construtor de um componente React é chamado antes do componente ser montado.
  • Ao implementar o construtor para um componente, devemos chamar super(props) antes de qualquer outra instrução. Caso contrário, this.props será indefinido no construtor, o que pode levar a erros.
  • Não se deve utilizar o setState() no construto, devemos atribuir o estado inicial diretamente em this.state

componentDidMount()

Este método é chamado logo após o componente ser montado(inserido na árvore).

Neste método você pode carregar dados de um endpoint remoto e chamar o setState(), alterando o valor do estado inicial do componente.

Embora o usuário não veja o estado intermediário do componente, pois isso acionará uma renderização extra, mas acontecerá antes que o navegador atualize a tela. Tome cuidado com este padrão, pois poderá ocorrer uma queda no desempenho, já que o método render() será chamado duas vezes.

render()

Este método é o único obrigatório no componente de classe.

Ele deve ser puro, o que significa que ele não modifica o estado do componente, retorna o mesmo resultado toda vez que é invocado e não interage diretamente com o navegador.

Se precisarmos interagir com o navegador, temos que executar as alterações no componentDidMount() ou nos outros métodos do ciclo de vida do componente.

Manter o render() puro torna os componentes mais fáceis de dar manutenção e de entender o que cada um faz.

componentDidUpdate()

Este método é chamado imediatamente após a atualização do componente.

Temos que tomar cuidado quando utilizarmos este método, pois qualquer atualização no componente gerará um novo render() e como o componente foi atualizado este método será chamado novamente e isso poderá causar um loop infinito, quebrando assim sua aplicação.

Temos que sempre comparar as propriedades atuais com as propriedades anteriores, para termos certeza que não iremos chamar a atualização várias vezes.

componentWillUnmount()

Este método é invocado imediatamente um componente ser destruído.

O utilizamos para limpar os timers, cancelar as solicitações e limpar tudo que foi criado ou instanciado no componentDidMount().

Não devemos alterar o state neste método, porque o componente nunca será renderizado novamente. Quando uma instância do componente é desmontada, ela nunca será montada novamente.

Podemos pesquisar mais sobre o ciclo de vida de um componente react neste link, http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/, ou na própria documentação do react https://reactjs.org/docs/react-component.html ou https://reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class

Métodos de Ciclo de Vida Raramente Utilizados

Os métodos que listarei agora raramente são utilizado e provavelmente muitos dos teus componentes não os utilizarão, porém eles podem ser úteis de vez em quando.

São eles:

  • shouldComponentUpdate(nextProps, nextState)
  • static getDerivedStateFromProps(props, state)
  • getSnapshotBeforeUpdate(prevProps, prevState)
  • componentDidCatch(error, info)

Métodos legados

A partir da versão 16.0 do react alguns métodos foram marcados como legados, você ainda pode utiliza-los, porém não é mais recomendado que faça isso em códigos novos.

São eles:

  • componentWillMount()
  • componentWillReceiveProps()
  • componentWillUpdate()

A documentação do react nos ensina a migrar os métodos legados para novos neste link, https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html.

Referências: