useRef
In useEffect, we saw a component reaching outside its render output.
This lesson covers another hook that solves a similar need -- "remembering"
a value without triggering the screen to update, or accessing a DOM
element directly: useRef.
DOM References
One of useRef's most common uses is accessing a DOM element directly:
import { useRef } from "react";
function DomReferenceExample() {
const inputRef = useRef(null);
function focusInput() {
// inputRef.current, gerçek DOM elementinin kendisi -- input'un
// sahip olduğu tarayıcı metotlarını (focus() gibi) doğrudan çağırabiliriz.
inputRef.current.focus();
}
return (
<div>
<input ref={inputRef} type="text" placeholder="Butona basınca odaklanır" />
<button onClick={focusInput}>Input'a Odaklan</button>
</div>
);
}
Writing ref={inputRef} tells React "put this element's real DOM node
into inputRef.current." inputRef.current is now a real DOM element --
we can call the browser's own methods on it directly, like focus().
Persistent Values Across Renders
useRef's second use: "remembering" a value across renders, without
that value changing triggering a RE-RENDER:
import { useState, useRef } from "react";
function PersistentValueExample() {
const [count, setCount] = useState(0);
const renderCount = useRef(0);
renderCount.current = renderCount.current + 1;
// renderCount.current değişiyor, ama bu bir RE-RENDER TETİKLEMEZ --
// yalnızca bir sonraki render'da güncel değeri gösterir.
return (
<div>
<p>Sayaç: {count}</p>
<p>Bu component şu ana kadar {renderCount.current} kez render oldu.</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
renderCount.current increases on every render and its value persists
across renders -- but that increase doesn't trigger a re-render on its
own. We only see the updated value on the NEXT render (triggered here
by the count state changing for another reason).
useRef vs. useState
The key difference between useRef and useState: changing state with
useState TRIGGERS a re-render, changing a ref does NOT:
import { useState, useRef } from "react";
function UseRefVsUseStateExample() {
const [stateValue, setStateValue] = useState(0);
const refValue = useRef(0);
function incrementState() {
setStateValue(stateValue + 1); // Ekranı günceller (re-render tetikler).
}
function incrementRef() {
refValue.current = refValue.current + 1;
console.log("refValue.current:", refValue.current);
// Değer gerçekten değişti, ama ekran GÜNCELLENMEZ -- çünkü ref
// değişikliği bir re-render tetiklemez.
}
return (
<div>
<p>State: {stateValue}</p>
<button onClick={incrementState}>State'i Artır</button>
<button onClick={incrementRef}>Ref'i Artır (Console'a Bak)</button>
</div>
);
}
Clicking "Increment State" updates the screen, because setStateValue
triggers a re-render. Clicking "Increment Ref" really does change the
value (you can see it in the console), but nothing changes on screen --
because a ref change doesn't tell React "re-render." A value that needs
to be VISIBLE on screen should be state; a value that just needs to be
"remembered," without appearing on screen, can be a ref.
Using useRef and useEffect Together
useRef and useEffect are often used together -- for example, to
answer "what was the value on the previous render":
import { useState, useEffect, useRef } from "react";
function PreviousValueWithRefExample() {
const [count, setCount] = useState(0);
const previousCountRef = useRef(undefined);
useEffect(() => {
// Her render'dan SONRA, mevcut değeri ref'e kaydediyoruz -- bir sonraki
// render'da "bir önceki değer" olarak okuyabilmek için. Bunun için
// state değil ref kullanıyoruz, çünkü bu kaydı ekranı yeniden
// render etmeden yapmak istiyoruz.
previousCountRef.current = count;
});
return (
<div>
<p>
Şimdiki: {count}, Önceki: {previousCountRef.current}
</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
The useEffect, which runs after every render, saves the current
count value into previousCountRef. On the next render, this ref
still holds the value from the PREVIOUS render -- because updating a
ref doesn't trigger a new render on its own; the update only happens
inside the render that's triggered by the count state changing.
Summary and Glossary
useRef is used for two main things: accessing a DOM element directly,
or remembering a value across renders without triggering the screen to
update. Unlike useState, changing a ref doesn't trigger a re-render --
so use useState for data that needs to be visible on screen, and
useRef for "background" values that don't.
Glossary
useRef — The hook that lets you access a DOM element, or store a
value across renders without triggering the screen to update.
.current — The field on the object useRef returns that holds
the currently stored value.
DOM Reference — Direct access to a JSX element's real browser DOM
node; set up with the ref attribute.