W kosmicznej podróży przez React, czasami potrzebujemy przechowywać informacje, które przetrwają między renderowaniami komponentu, ale nie powinny powodować ponownego renderowania. Hook useRef jest jak kapsuła ratunkowa - przechowuje dane, które możesz odzyskać w dowolnym momencie, bez względu na to, ile razy twój statek kosmiczny (komponent) zostanie przebudowany.
Hook
useRef tworzy mutowalny obiekt referencyjny, którego właściwość .current jest inicjalizowana przekazaną wartością. Ważną cechą useRef jest to, że:Porównajmy dwie kluczowe metody przechowywania danych w komponentach:
1function SpaceshipDashboard() {
2 // Stan - zmiany powodują ponowne renderowanie
3 const [speed, setSpeed] = useState(0);
4
5 // Referencja - zmiany NIE powodują ponownego renderowania
6 const previousSpeedRef = useRef(0);
7
8 // Przy zmianie prędkości, zapisujemy poprzednią wartość
9 useEffect(() => {
10 previousSpeedRef.current = speed;
11 }, [speed]);
12
13 const increaseSpeed = () => {
14 setSpeed(speed + 10); // To spowoduje ponowne renderowanie
15 };
16
17 return (
18 <div>
19 <p>Aktualna prędkość: {speed} km/h</p>
20 <p>Poprzednia prędkość: {previousSpeedRef.current} km/h</p>
21 <button onClick={increaseSpeed}>Zwiększ prędkość</button>
22 </div>
23 );
24}Jednym z najpopularniejszych zastosowań useRef jest zapamiętywanie poprzednich wartości między renderowaniami:
1function AsteroidTracker({ asteroid }) {
2 const [position, setPosition] = useState({ x: 0, y: 0 });
3 const previousPositionRef = useRef({ x: 0, y: 0 });
4
5 useEffect(() => {
6 // Zapisujemy aktualną pozycję jako poprzednią przed następną aktualizacją
7 previousPositionRef.current = position;
8 }, [position]);
9
10 // Obliczamy, jak daleko poruszył się asteroid
11 const distanceMoved = Math.sqrt(
12 Math.pow(position.x - previousPositionRef.current.x, 2) +
13 Math.pow(position.y - previousPositionRef.current.y, 2)
14 );
15
16 return (
17 <div>
18 <p>Aktualna pozycja: ({position.x}, {position.y})</p>
19 <p>Poprzednia pozycja: ({previousPositionRef.current.x}, {previousPositionRef.current.y})</p>
20 <p>Przebyta odległość: {distanceMoved}</p>
21 </div>
22 );
23}1function MissionControl() {
2 const missionTimeRef = useRef(0);
3 const timerIdRef = useRef(null);
4
5 // Rozpoczęcie licznika misji
6 const startMissionTimer = () => {
7 if (timerIdRef.current !== null) return; // Unikamy wielokrotnego uruchamiania
8
9 timerIdRef.current = setInterval(() => {
10 missionTimeRef.current += 1;
11 console.log(\`Czas misji: \${missionTimeRef.current} sekund\`);
12 // Zauważ, że to NIE powoduje ponownego renderowania komponentu
13 }, 1000);
14 };
15
16 // Zatrzymanie licznika misji
17 const stopMissionTimer = () => {
18 clearInterval(timerIdRef.current);
19 timerIdRef.current = null;
20 };
21
22 // Czyszczenie przy odmontowaniu komponentu
23 useEffect(() => {
24 return () => {
25 if (timerIdRef.current !== null) {
26 clearInterval(timerIdRef.current);
27 }
28 };
29 }, []);
30
31 return (
32 <div>
33 <button onClick={startMissionTimer}>Rozpocznij misję</button>
34 <button onClick={stopMissionTimer}>Zakończ misję</button>
35 <button onClick={() => alert(\`Czas misji: \${missionTimeRef.current} sekund\`)}>
36 Pokaż czas misji
37 </button>
38 </div>
39 );
40}1function SpaceshipScanner() {
2 const scannerInputRef = useRef(null);
3
4 const focusScannerInput = () => {
5 // Bezpośredni dostęp do elementu DOM
6 scannerInputRef.current.focus();
7 };
8
9 return (
10 <div>
11 <input
12 ref={scannerInputRef}
13 type="text"
14 placeholder="Wprowadź współrzędne..."
15 />
16 <button onClick={focusScannerInput}>Aktywuj skaner</button>
17 </div>
18 );
19}Hook useRef jest nieoceniony, gdy potrzebujesz:
Jak kapsuła ratunkowa w kosmosie, useRef przechowuje cenne dane, które mogą być potrzebne w krytycznych momentach misji twojego komponentu.