hooks

Understanding How Some React Hooks Work

Sep 24, 2021
Understanding How Some React Hooks Work

React Hooks

Understanding How Some React Hooks Work

Como rodar o projeto:

Você pode clonar o projeto e rodá-lo localmente seguindo os passos abaixo

  1. git clone https://github.com/rafaballerini/ReactHooks.git para clonar o projeto
  2. yarn para instalar as dependências do projeto
  3. yarn start
  4. Acessar http://localhost:3000 no navegador

Como testar cada um dos hooks:

  1. Abra o arquivo App.js. É possível perceber que existem várias linhas comentadas, tanto na parte de importações, quando dentro da função.
  2. Descomente a importação referente ao hook que deseja testar e também a linha dentro da função (há outro comentário no final da linha indicando a qual hook ela pertence).

Explicação de cada Hook:

useState

É uma função para controle de estado:

  • recebe um parâmetro (valor inicial desse estado)
  • retorna uma lista com 2 variáveis (a primeira é o valor do estado em si e a segunda é a função que atualiza esse estado)
const [state, setState] = useState(0);

O setState será usado para atualizar os valores do estado, por exemplo:

function increment(){ setState(state + 1) }

useEffect

  • recebe dois parâmetros: uma função e uma lista de dependências. Quando algum elemento dessa lista for alterado, a função é executada automaticamente.
  • o retorno da função pode ser uma função. Se for, ela será executada quando o componente for desmontado
useEffect(() => { console.log(state) }, [state])

Quando a lista de dependências estiver vazia, a função será executada no momento que o componente for renderizado.
É executado de forma assíncrona depois de uma renderização na tela.

useContext

É uma forma de mais de um componente ter acesso a uma funcionalidade/lógica do programa.
Pra isso é criado uma const Context usando o React.createContext.

const Context = createContext()

Criamos um componente que será o provedor dos dados que tem no nosso context.

export function PageContextProvider({children}) { const [state, setState] = useState(0); const increment = useCallback(()=>{ setState(state + 1) },[state]) const decrement = useCallback(()=>{ setState(state - 1) },[state]) const handleChange = useCallback((event)=>{ setState(Number(event.target.value)) },[state]) return ( <Context.Provider value={{ state, increment, decrement, handleChange} }> {children} </Context.Provider> ) }

Note que esse Context.Provider recebe a propriedade children e utiliza essa propriedade para representar todos os componentes.

<PageContextProvider> <PageInputContext/> </PageContextProvider>

PageInputContext é um componente filho de PageContextProvider e para acessar as propriedades que ele envia é preciso chamar o useContext passando como parâmetro o Context, criado com o React.createContext

export default function PageInputContext(){ const {state, increment, decrement, handleChange} = useContext(Context) }

useReducer

No useState a lógica de atualização de dados fica dentro de onde ele foi chamado, já no UseReducer a lógica ficará em uma função, como essa reducer abaixo.

function reducer(state, action) { switch (action.type) { case "increment": return state + 1; case "decrement": return state - 1; default: return action.newState; } }
  • recebe até 3 parâmetros: o primeiro é a função que altera o estado, o segundo é o estado inicial e o terceiro é uma função init caso seja necessário executar alguma coisa no momento que o estado é criado
  • retorna uma lista com 2 elementos: o valor do estado em si e o dispatch, que é a forma como iremos chamar a função para atualizar o estado, ela que dispara a chamada da função reducer
const [state, dispatch] = useReducer(reducer, 0);

Normalmente é melhor utilizar o useReducer quando se tem uma lógica complexa no state que envolve múltiplos subvalores ou quando o próximo state depende do anterior.
Ele também permite otimizar performance para alguns componentes, pois você pode passar um dispatch ao invés de callbacks.

<button onClick={() => dispatch({ type: "decrement" })}>

useCallback

Para cada alteração no valor do state, criamos um callback diferente: increment, decrement e handleChange

  • recebe 2 parâmetros: uma função e uma lista de dependências. Essa função é memorizada e apenas será rerenderezida quando um dos valores da lista de dependências for alterado.
const increment = useCallback(()=>{ setState(state + 1) },[state]) const decrement = useCallback(()=>{ setState(state - 1) },[state]) const handleChange = useCallback((event)=>{ setState(Number(event.target.value)) },[state])

A função não ser recarregada toda hora facilita muito o processamento.

useMemo

Assim como o useCallback:

  • recebe 2 parâmetros: uma função e uma lista de dependências.
const memorizedValue = useMemo(() => { if(state > state2){ return 'Maior' }else if(state < state2){ return 'Menor' }else{ return 'Igual' } }, [state, state2])

O valor de retorno da função é memorizado e apenas será recarregado quando um dos valores da lista de dependências forem alterados.

useRef

  • retorna a referência de um objeto mutável e que existirá durante toda a vida do componente.
export default function InputTexto() { const inputRef = useRef(null); const focaInput = () => { inputRef.current.focus(); }; return ( <div className="content refContent"> <input ref={inputRef} type="text" /> <button className="focusButton" onClick={focaInput}>Dá foco no input</button> </div> ); }

Para acessar o objeto é necessário usar a propriedade .current do useRef.

useImperativeHandle

Utilizado para passar um componente ref para um componente pai, devendo ser combinado com o fowardRef.

function InputTextoImperative(props, ref) { const inputRef = useRef(null); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); }, console: () => { console.log('teste') } })); return ( <div className="content"> <input ref={inputRef} type="text" /> </div> ); } export default forwardRef(InputTextoImperative);

Você pode colocar um botão em App.js (componente pai) e ele chamar a função do componente filho.

<InputTextoImperative ref={inputRef}/> <button className="focusButton" onClick={focaInput}>Dá foco no input</button>

useLayoutEffect

É muito parecido com o useEffect, porém é disparado de forma síncrona após todas as mudanças no DOM e antes de aparecer qualquer coisa na tela.

useLayoutEffect(() => { console.log('layout'); }, [])

É preferível utilizar o useEffect para evitar bloqueio de atualizações visuais.

Quando usar?
Você vai perceber que o elemento ficará piscando/executando várias vezes quando utilizar o useEffect, nesse caso o ideal é alterar para useLayoutEffect.

useDebugValue

Utilizado em conjunto com a extensão React Dev Tools para mostrar o conteúdo de algum estado, como se fosse um console.log.

function useAnalyzeState(state) { useDebugValue(`Valor do state = ${state}`); return state; }

Como o próprio nome diz, é utilizado para fazer debug.

GitHub

https://github.com/rafaballerini/ReactHooks

Recommended