Já podemos utilizar Hooks no React, oReact Hooks? Antes de respondermos essa pergunta, você já sabe o que é Hooks? Se não, vamos juntos tentar entender melhor sobre este novo recurso.
Resumidamente, Hooks é uma nova proposta que irá nos permitir utilizar estado, ciclo de vida, entre outras funcionalidades, sem a necessidade de escrevermos componentes com classe. A proposta já foi aceita e está disponível na versão 16.8 do React.
Então vamos entender melhor como os Hooks irão mudar e impactar o desenvolvimento de UI com React Hooks.
Motivação
Os Hooks resolvem uma grande variedade de problemas encontrados durante o desenvolvimento de componentes. Por exemplo:
Reutilização de lógica de estado entre components;
Wrapper Hell (HOC, Render props — React DevTools);
Componentes complexos e difíceis de se compreender;
Componentes contendo grandes responsabilidades;
Confusão ao utilizar classes (this, classes).
Antes de continuarmos, um pouquinho sobre Typescript
Ele vem dominando e tendo uma grande imersão em aplicações que anteriormente só utilizavam JavaScript. Que tal já escrevermos nossos exemplos em Typescript (TS), para nos acostumarmos com os tipos?
O Typescript fornece um sistema de tipos para JavaScript, dando a oportunidade de checarmos nossos tipos em tempo de desenvolvimento. Type check tem provado aprimorar a qualidade, compreensibilidade e manutenção do código.
Cenário anterior
Imagine que você tenha um componente sem estado e ciclo de vida e, a partir deste momento, por alguma necessidade, precise desses recursos em seu componente?
import React from 'react'
interface Props {
counter: number
}
function Counter({ counter }: Props) {
return <p>{counter}</p>
}
export default Counter
No componente acima, apenas mostramos a propriedade counter recebida via props. Agora vamos necessitar de um estado local que será responsável por manter o valor do count. Surgindo essa necessidade, também aparece a obrigatoriedade de reescrevermos com classe.
Componente Counter com Classe:
import React, { Component } from 'react'
interface Props {
initialCount: number
}
interface State {
count: number
}
class CounterClass extends Component<Props, State> {
constructor(props: Props) {
super(props)
const { initialCount } = props
this.state = {
count: initialCount
}
this.increment = this.increment.bind(this)
}
increment() {
this.setState({ count: this.state.count + 1 })
}
render() {
const { count } = this.state
return (
<button onClick={this.increment}>{count}</button>
)
}
}
export default CounterClass
Trocando Class por Hooks
Agora temos a mesma lógica do componente anterior com Hooks. É notável a redução de escrita e a facilidade para compreender melhor como o componente irá se comportar.
import React, { useState } from 'react'
interface Props {
initialCount: number
}
function CounterHooks ({ initialCount }: Props) {
const [count, setCount] = useState(initialCount)
const increment = () => setCount(count + 1)
return <button onClick={increment}>{count}</button>
}
export default CounterHooks
Extinção das classes?
Não é necessário reescrever todo o seu código para que ele seja escrito utilizando Hooks, mas já relataram que pretendem, no futuro, retirar o suporte às classes do package react, repassando essa responsabilidade para uma lib distinta.
Então se você gosta de escrever seus componentes com classe, não se preocupe, irão manter nessa lib o Component e PureComponent.
Estado
useState
Como já vimos no exemplo anterior, essa é a forma como iremos definir nosso estado em nossos componentes.
useReducer
É uma alternativa para mantermos nosso estado quando o mesmo é mais complexo. Se você conhece a sintaxe do redux, a mesma é utilizada no useReducer.
Algo que deve ser mencionado é que aqui não temos a propagação do estado por toda a aplicação como o redux proporciona. Caso queira algo similar, terá que utilizar useContext.
Ciclos de vida
useEffect
Este será responsável por nos ajudar a lidar com side effects em nossa aplicação, ele irá substituir os ciclos de vida que tínhamos anteriormente.
O primeiro parâmetro do useEffect é uma função de callback que irá ser disparada quando o componente for montado.
Também irei listar um pequeno exemplo de como utilizaríamos com classe e agora com Hooks:
ComponentDidMount
// componentDidMount com class
import React, { Component } from 'react'
class DidMount extends Component {
componentDidMount() {
console.log('Eu estou montado')
}
render() {
return <>content</>
}
}
export default DidMount
Inicialmente, pode parecer bem estranho, para termos o efeito de componentDidMount com Hooks é necessário passar um array vazio como segundo parâmetro para o Hook useEffect.
// componentDidMount com hooks
import React, { useEffect } from 'react'
function DidMount() {
useEffect(() => console.log('Eu estou montado'), [])
return <>content</>
}
export default DidMount
ComponentDidUpdate
import React, { Component } from 'react'
interface State {
name: string
}
class DidUpdate extends Component<{}, State> {
state = {
name: ''
}
componentDidMount() {
console.log('Eu estou montado')
}
componentDidUpdate() {
console.log('Sofri alteração')
}
handleChange = (e: React.ChangeEvent<HTMLInputElement>) =>
this.setState({ name: e.target.value })
render() {
const { name } = this.state
return (
<>
<input value={name} onChange={this.handleChange} />
</>
)
}
}
export default DidUpdate
Similar ao que temos no componentDidMount com hooks, precisamos passar os valores de estado e props dentro de um array no segundo parâmetro da função useEffectpara mantermos o efeito do ciclo componentDidUpdate.
Observação: neste caso, não é necessário nem informar o tipo do estado name, pois o Typescript já infere para nós que é uma string quando iniciamos o estado com um texto vazio.
import React, { useEffect, useState } from 'react'
function DidUpdate() {
const [name, setName] = useState('')
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => setName(e.target.value)
useEffect(() => {
console.log('Eu estou montado ou sofri alteração')
}, [name])
return (
<>
<input value={name} onChange={handleChange} />
</>
)
}
export default DidUpdate
ComponentWillUnmount
import React, { Component } from 'react'
class WillUnmount extends Component {
componentDidMount() {
console.log('Eu estou montado')
}
componentWillUnmount() {
console.log('Vou desmontar')
}
render() {
return (
<>
...Content
</>
)
}
}
export default WillUnmount
ComponentWillUnmount com hooks
import React, { useEffect } from 'react'
function WillUnmount() {
useEffect(() => {
console.log('Eu estou montado')
return () => {
console.log('Vou desmontar')
}
}, [])
return (
<>
...Content
</>
)
}
export default WillUnmount
Você deve ter notado que para todos os três métodos que utilizávamos anteriormente, o useEffect engloba os mesmos efeitos em um único Hook. O retorno e os parâmetros do useEffect são o que diferenciam seu comportamento.
Custom Hooks
Você também é livre para criar seus próprios Hooks podendo compartilhar lógica entre componentes.
Este é o pulo do gato, use sempre que necessário!
import React, { useState } from 'react'
interface Props {
initialState: number,
step: number
}
function useCounter({ initialState, step }: Props) {
const [count, setCount] = useState(initialState)
const increment = () => setCount(count + step)
return { count, increment }
}
function Counter() {
const { count, increment } = useCounter({ initialState: 0, step: 1 })
return <button onClick={increment}>{count}</button>
}
export default Counter
Hooks cobrem todos os ciclos anteriores?
Não, existem alguns fluxos que os Hooks ainda não suportam como:
getDerivedStateFromError;
componentDidCatch;
getSnapshotBeforeUpdate.
Estes devem ser implementados em um futuro próximo e, se por acaso precisar, deverá ainda utilizar classes nestes casos.
Regras e resumo sobre Reack Hooks
Algumas regras devem ser cumpridas na utilização de Hooks:
- Não utilize Hooks em loops;
- Não utilize Hooks em condições;
- Declare seus Hooks no topo do componente.
Para manter este padrão e evitar problemas, existe um plug-in do eslint que pode te auxiliar e evitar o uso incorreto dos Hooks:
– eslint-plugin-react-hooks
Em outras palavras: Se você gosta de escrever seus componentes com classe, use React Hooks.
Se algo escrito aqui precisa ser corrigido ou se deseja complementar o conteúdo, não deixe de comentar. Vamos compartilhar conhecimento e enriquecer a nossa comunidade.
Já podemos utilizar Hooks no React, oReact Hooks? Antes de respondermos essa pergunta, você já sabe o que é Hooks? Se não, vamos juntos tentar entender melhor sobre este novo recurso.
Resumidamente, Hooks é uma nova proposta que irá nos permitir utilizar estado, ciclo de vida, entre outras funcionalidades, sem a necessidade de escrevermos componentes com classe. A proposta já foi aceita e está disponível na versão 16.8 do React.
Então vamos entender melhor como os Hooks irão mudar e impactar o desenvolvimento de UI com React Hooks.
Motivação
Os Hooks resolvem uma grande variedade de problemas encontrados durante o desenvolvimento de componentes. Por exemplo:
Reutilização de lógica de estado entre components;
Wrapper Hell (HOC, Render props — React DevTools);
Componentes complexos e difíceis de se compreender;
Componentes contendo grandes responsabilidades;
Confusão ao utilizar classes (this, classes).
Antes de continuarmos, um pouquinho sobre Typescript
Ele vem dominando e tendo uma grande imersão em aplicações que anteriormente só utilizavam JavaScript. Que tal já escrevermos nossos exemplos em Typescript (TS), para nos acostumarmos com os tipos?
O Typescript fornece um sistema de tipos para JavaScript, dando a oportunidade de checarmos nossos tipos em tempo de desenvolvimento. Type check tem provado aprimorar a qualidade, compreensibilidade e manutenção do código.
Cenário anterior
Imagine que você tenha um componente sem estado e ciclo de vida e, a partir deste momento, por alguma necessidade, precise desses recursos em seu componente?
No componente acima, apenas mostramos a propriedade counter recebida via props. Agora vamos necessitar de um estado local que será responsável por manter o valor do count. Surgindo essa necessidade, também aparece a obrigatoriedade de reescrevermos com classe.
Componente Counter com Classe:
Trocando Class por Hooks
Agora temos a mesma lógica do componente anterior com Hooks. É notável a redução de escrita e a facilidade para compreender melhor como o componente irá se comportar.
Extinção das classes?
Não é necessário reescrever todo o seu código para que ele seja escrito utilizando Hooks, mas já relataram que pretendem, no futuro, retirar o suporte às classes do package react, repassando essa responsabilidade para uma lib distinta.
Então se você gosta de escrever seus componentes com classe, não se preocupe, irão manter nessa lib o Component e PureComponent.
Estado
useState
Como já vimos no exemplo anterior, essa é a forma como iremos definir nosso estado em nossos componentes.
useReducer
É uma alternativa para mantermos nosso estado quando o mesmo é mais complexo. Se você conhece a sintaxe do redux, a mesma é utilizada no useReducer.
Algo que deve ser mencionado é que aqui não temos a propagação do estado por toda a aplicação como o redux proporciona. Caso queira algo similar, terá que utilizar useContext.
Ciclos de vida
useEffect
Este será responsável por nos ajudar a lidar com side effects em nossa aplicação, ele irá substituir os ciclos de vida que tínhamos anteriormente.
O primeiro parâmetro do useEffect é uma função de callback que irá ser disparada quando o componente for montado.
Também irei listar um pequeno exemplo de como utilizaríamos com classe e agora com Hooks:
ComponentDidMount
Inicialmente, pode parecer bem estranho, para termos o efeito de componentDidMount com Hooks é necessário passar um array vazio como segundo parâmetro para o Hook useEffect.
ComponentDidUpdate
Similar ao que temos no componentDidMount com hooks, precisamos passar os valores de estado e props dentro de um array no segundo parâmetro da função useEffectpara mantermos o efeito do ciclo componentDidUpdate.
Observação: neste caso, não é necessário nem informar o tipo do estado name, pois o Typescript já infere para nós que é uma string quando iniciamos o estado com um texto vazio.
ComponentWillUnmount
ComponentWillUnmount com hooks
Você deve ter notado que para todos os três métodos que utilizávamos anteriormente, o useEffect engloba os mesmos efeitos em um único Hook. O retorno e os parâmetros do useEffect são o que diferenciam seu comportamento.
Custom Hooks
Você também é livre para criar seus próprios Hooks podendo compartilhar lógica entre componentes.
Este é o pulo do gato, use sempre que necessário!
Hooks cobrem todos os ciclos anteriores?
Não, existem alguns fluxos que os Hooks ainda não suportam como:
getDerivedStateFromError;
componentDidCatch;
getSnapshotBeforeUpdate.
Estes devem ser implementados em um futuro próximo e, se por acaso precisar, deverá ainda utilizar classes nestes casos.
Regras e resumo sobre Reack Hooks
Algumas regras devem ser cumpridas na utilização de Hooks:
Para manter este padrão e evitar problemas, existe um plug-in do eslint que pode te auxiliar e evitar o uso incorreto dos Hooks:
– eslint-plugin-react-hooks
Em outras palavras: Se você gosta de escrever seus componentes com classe, use React Hooks.
Se algo escrito aqui precisa ser corrigido ou se deseja complementar o conteúdo, não deixe de comentar. Vamos compartilhar conhecimento e enriquecer a nossa comunidade.