Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Hooks: o que é e como funciona? #11

Open
Manoeldevcertsys opened this issue Feb 28, 2023 · 0 comments
Open

React Hooks: o que é e como funciona? #11

Manoeldevcertsys opened this issue Feb 28, 2023 · 0 comments

Comments

@Manoeldevcertsys
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant