React Hooks: O que são e porque eles são importantes
javascript • reactHoje vamos conversar sobre React Hooks. O que são, porque são importantes e como eles mudam a forma como escrevemos nossos componentes com react.
O que são Hooks
Os Hooks no react são uma nova funcionalidade proposta pelo pessoal do Facebook, que nos deixa usar o state e outras features do React como os métodos do ciclo de vida, sem precisarmos escrever uma class.
A motivação
Os componentes e o fluxo de dados de cima para baixo nos ajudam a organizar uma interface de usuário grande em partes pequenas, independentes e reutilizáveis.
O React é uma lib fantástica que nos permite construir interfaces componentizadas com grande facilidade, porém em alguns momentos é bem difícil reaproveitar a lógica entre componentes por que ela é stateful e não pode ser extraída para uma função ou outro componente.
Quando tentamos resolver esses casos de uso apenas com componentes, geralmente acabamos com:
- Componentes enormes que são difíceis de refatorar e testar;
- Lógica duplicada entre diferentes componentes e métodos de ciclo de vida;
- Padrões complexos como render props e High order components;
- E o Wrapper hell;
Hoje, para criarmos um componente stateful, obrigatoriamente temos que declarar uma class. Mas e se pudéssemos usar state em uma function componente?
Como hooks podemos fazer isso, e vamos ver isso agora, mas antes de você sair correndo e gritando para o mundo que as classes vão ser depreciadas no React:
TLDR: Não há planos para remover classes do React.
React Hooks
Como já dei o spoiler antes, os Hooks nos deixam usar o state e outras features do React como os métodos do ciclo de vida, sem precisarmos escrever uma class.
Mas não é só isso, também conseguimos usar o Context sem cair no Wrapper hell. Vamos ver como funciona:
Aqui temos o nosso componente, stateful que tem o nosso state, com o name
e o lastname
. Nosso componente também consome 2 contextos, ThemeContext
e LocaleContext
um dele é o tema e outro é o idioma.
import React, { Component } from 'react';
import Row from '../Row/Row';
import { ThemeContext, LocaleContext } from '../../context';
import './card.scss';
export default class Card extends Component {
constructor(props) {
super(props);
this.state = {
name: 'Jubileu',
lastname: 'Pipoca'
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({
[e.target.id]: e.target.value
})
}
render() {
return (
<ThemeContext.Consumer>
{({theme}) => (
<section className={theme}>
<Row label="Nome">
<input
id="name"
value={this.state.name}
onChange={this.handleChange}
/>
</Row>
<Row label="Sobrenome">
<input
id="lastname"
value={this.state.lastname}
onChange={this.handleChange}
/>
</Row>
<Row label="Idioma">
<LocaleContext.Consumer>
{({ locale }) => (
<p>{locale}</p>
)}
</LocaleContext.Consumer>
</Row>
</section>
)}
</ThemeContext.Consumer>
);
}
}
Agora vamos escrever o mesmo componente, utilizado Hooks e vamos observar as diferenças.
import React, { useState, useContext } from 'react';
import Row from '../Row/Row';
import { ThemeContext, LocaleContext } from '../../context';
import './card.scss';
export default function CardWithHooks() {
const [name, setName ] = useState('Jubileu');
const [lastname, setLastname ] = useState('Pipoca');
const { theme } = useContext(ThemeContext);
const { locale } = useContext(LocaleContext);
function handlerChangeName(e) {
setName(e.target.value)
}
function handlerChangeLastname(e) {
setLastname(e.target.value)
}
return (
<section className={theme}>
<Row label="Nome">
<input
id="name"
value={name}
onChange={handlerChangeName}
/>
</Row>
<Row label="Sobrenome">
<input
id="lastname"
value={lastname}
onChange={handlerChangeLastname}
/>
</Row>
<Row label="Idioma">
<p>{locale}</p>
</Row>
</section>
);
}
A primeira coisa que notamos é que nosso componente é apenas uma função, e não mais uma classe. Para usarmos o state dentro no nosso compoente, importamos o hook useState
:
import React, { useState } from 'react';
E no nosso compoente, usamos o hook da seguinte forma:
const [name, setName ] = useState('Jubileu');
No exemplo acima, declaramos o valor, no caso o name
e o método que setá esse valor setName
. O valor inicial é passado como argumento para nosso hook useState('Jubileu')
. Hooks nada mais são que funções.
Outra coisa muito bacana é que quando usamos o useContext
hook, eliminamos o wrapper hell, e usamos da mesma forma que usamos o state:
import React, { useContext } from 'react';
// código omitido
const { theme } = useContext(ThemeContext);
Esses são apenas 2 exemplos de uso dos hooks do react, as possibilidades são muitas.
Lifecycle
Imagine que precisamos atualizar o title da página com o nome e sobre nome do usuário conforme ele digita nos inputs, do modo convencional, usariamos 2 métodos do ciclo de vida do React: componentDidMount
e componentDidUpdate
, para setarmos o valor inicial e atualizá-lo sempre que o state for atualizado.
// código omitido
componentDidMount() {
document.title = this.state.name + ' ' + this.state.lastname;
}
componentDidUpdate() {
document.title = this.state.name + ' ' + this.state.lastname;
}
// código omitido
Com hooks, podemos fazer a mesma coisa de uma forma mais simples, e também em um function component. Neste caso, usamos o useEffect
.
O Effect Hook, useEffect, adiciona a capacidade de realizar efeitos colaterais de um function component. Ele serve o mesmo propósito que componentDidMount
, componentDidUpdate
e componentWillUnmount
nas classes React, mas unificado em uma única API.
Para usá-lo, importamos ele e usamos da seguinte forma:
import React, { useEffect } from 'react';
// código omitido
useEffect(() => {
document.title = name.value + ' ' + lastname.value;
});
// código omitido
Desta forma, o title da página será alterado quando o componente for montado no DOM e toda a vez que ele for atualizado, a alteração será feita no title da página também. Fácil não? :)
Mais uma coisa
Antes de finalizarmos, vamos melhorar nossa reutilização de código e legibilidade do nosso componente, criando um hook customizado.
Vamos separar o gerenciamento do nosso state e a alteração do state em um hook customizado, que pode ser usado por qualquer input dentro da nossa aplicação.
import React, { useState } from 'react';
// Custom React Hook
function useFormInput(initialValue) {
const [value, setValue] = useState(initialValue);
function handlerChange(e) {
setValue(e.target.value);
}
return {
value: value,
onChange: handlerChange
}
}
Vamos analisar esse hook.
Recebemos como argumento o valor inicial do nosso input, usamos o hook useState
, declaramos um método que seta o valor quando ele for atualizado e por fim, retornamos um objeto com o value e o evento de change.
Após essa alteração, veja como nosso componente ficou bem mais legível e mais enxuto:
import React, { useContext, useEffect } from 'react';
import { ThemeContext, LocaleContext } from '../../context';
import Row from '../Row/Row';
import useFormInput from '../hooks/useFormInput';
import './card.scss';
export default function CardWithHooks() {
const name = useFormInput('Jubileu');
const lastname = useFormInput('Pipoca');
const { theme } = useContext(ThemeContext);
const { locale } = useContext(LocaleContext);
useEffect(() => {
document.title = name.value + ' ' + lastname.value;
});
return (
<section className={theme}>
<Row label="Nome">
<input id="name" {...name} />
</Row>
<Row label="Sobrenome">
<input id="lastname" {...lastname} />
</Row>
<Row label="Idioma">
<p>{locale}</p>
</Row>
</section>
);
}
Considerações finais
Apesar que Hooks do react ainda são uma versão alpha, o Facebook tem usado a cerca de 1 mês em produção já, então não serão esperados grandes problemas, mas eles alertam para que você não reescreva seus componentes usando hooks ainda, pois a feature ainda é uma proposta e muita coisa pode mudar.
Alguns pontos muito importantes sobre os hooks:
- Os hooks são 100% retrocompatíveis, ou seja, não vão quebrar seus componentes atuais;
- São completamente opcionais;
- Eles podem ser usados lado a lado com class components;
- Novas APIs propostas;
- O pessoal do React precisa do feedback dos desenvolvedores;
Caso queira entender mais sobre os Hooks, acesse a documentação oficial e contribua para a evolução dos hooks.
O exemplo que criamos aqui é bem simples, mas é uma boa introdução aos Hooks. Ele está disponível no github, baixe e faça seus testes.
Caso tenha dúvidas, comente aqui embaixo que terei o prazer de responder.
Até mais e obrigado pelos peixes.
Comentários