Interpretando o ReactJS - Hook useRef

Author: Ikidon


Como todo programador Front-end, conheci o ReactJS, e como um bom curioso busquei mais conhecimento sobre essa biblioteca incrível, queria ver implementações diferentes e detalhes que para muitos são inrelevante, gosto sempre de ver como funciona o interior, e nessa postagem, queria compartilhar conhecimento sobre o hook useRef dessa lib que tanto usamos atualmente.

Do Começo

O hook useRef, é uma forma elegante e simples de armazenar valores sem que seja disparado uma nova renderização.

Já vi alguns programadores usar esse hook de forma errada, até mesmo de forma excessiva, mas se posso indicar algo, indicarei que usem para coisas simples.

Existem alguns gatilhos que naturalmente irá nos fazer usa-lo, como referenciar um elemento na arvore DOM e ter acesso a ele, de forma que possamos manipular o mesmo posteriormente.

Nesse exemplo, o useRef é usado para referenciar a tag video, que posteriormente usamos para manipular os controles da tag.

import { useRef } from 'react'

function Video() {
    const videoRef = useRef(null)
    
    function handlerPlay() {
        videoRef.current.play()
    }
    
    function handlerPause() {
        videoRef.current.pause()
    }
    
    return (
        <div>
            <video ref={videoRef}>
                <source 
                    src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
                    type="video/mp4"
                />
            </video>
            
            <button onClick={handlerPlay}>Play</button>
            <button onClick={handlerPause}>Pause</button>
        </div>
    )
}

Por que devo usar o useRef, se posso declarações padrões?

O useRef tem um fluxo persistente a renderização, ou seja, seu valor se mantem mesmo que o componente tenha que ter uma nova renderização em algum momento, já as declarações padrão são descartadas e reescritas novamente em cada renderização.

Nesse exemplo, o retorno do console sempre será 1, já que como a cada ciclo a variavél sempre é reescrita, ela sempre retorna a 0 e depois é somado a 1.

import { useRef } from 'react'

function App() {
    const [ _, setState] = React.useState(false)
    let contador = 0;
        
    contador += 1;
    
    function handler() {    
        setState(state => !state)
        console.log(contador)
    }

    return <button onClick={handler}>Novo ciclo</button>
}

Já nesse outro exemplo, o retorno é um contador crescente, porque como mencionado antes a referencia é persistente entre os ciclos de renderizações.

import { useRef } from 'react'

function App() {
    const [ _, setState] = useState(false)
    let count = React.useRef(0);
    
    useEffect(() => {
        count.current += 1;        
    },[])

    function handlerCounter() {
        setState(state => !state)
        console.log(contador.current)
    }

    return <button onClick={handler}>Novo ciclo</button>
}

Atenção nos detalhes

O React busca que cada componente seja uma função pura, isso quer dizer que diante dos mesmos valores ela deve se comporta igualmente.

Seguindo a ideia de função pura, não podemos ler ou escrever sobre as referencias, durante o ciclo de renderização, porque isso pode causar uma ação inesperada.

No exemplo do contador, usei um novo hook o useEffect para poder alterar o valor do useRef, posteriormente irei falar sobre ele, mas uma breve explicação sobre ele só para seguimos, o useEffect ele dispara uma função assim que o componente termina de ser renderizado.

Ler e escrever durante a renderização, poderá sair da regra de função pura.

import { useRef } from 'react'

function App() {
    const count = useRef(0)
    
    // não faça isso
    count.current += 1;
    
    // faça isso
    useEffect(() => {
        count.current += 1
    }, [])
    
    // ou faça isso
    function handlerCounter() {
        count.current += 1
        setState(state => !state)
        console.log(contador.current)
    }
    
    // Não faça isso
    return <button onClick={handlerCounter}>Novo Ciclo {count.current}</button>
}

Considerações finais

Esse poster é mais uma forma de compartilha como eu vejo esse hook, então se tiver algo errado, ou alguma outra abordagem melhor ou mais simples, por favor compartilhe.

Criticas construtivas serão sempre bem vindas aqui. ^^ Obrigado por ler.