✨ 값을 저장하고 활용하는 방법 중 useState와 비교되는 useRef!
useState
와 더불어 특정 값을 저장하기 위해 사용되는 대표적인 hook
입니다.
`Re-rendering과 상관없이 값을 기억하기 위해 사용되는 것이 본질적 특징입니다.
이 특징을 이용해 자바스크립트 DOM API
를 직접사용하지 않고
DOM
요소를 다루기 위한 용도로도 자주 사용됩니다.
import "./App.css";
import { useRef } from "react";
function App() {
const ref = useRef("초기값");
console.log("ref", ref);
return (
<div>
<p>useRef에 대한 이야기에요.</p>
</div>
);
}
export default App;
콘솔을 확인해보면, ref
에는 값이 담겨있다.
ref {current: '초기값'}
그리고 변경도 가능합니다.
import "./App.css";
import { useRef } from "react";
function App() {
const ref = useRef("초기값");
console.log("ref 1", ref);
ref.current = "바꾼 값";
console.log("ref 1", ref);
return (
<div>
<p>useRef에 대한 이야기에요.</p>
</div>
);
}
export default App;
콘솔은 다음과 같다.
ref {current: '초기값'}
ref {current: '바꾼 값'}
이렇게 설정된 ref
값은 컴포넌트가 계속해서 렌더링 되어도
unmount
전까지 값을 유지합니다.
이러한 특징 때문에 useRef
는 다음 2가지 용도로 사용되는데
1. state와 비슷한 역할을 해요.
다만 state는 변화가 일어나면 다시 렌더링이 일어납니다.
내부 변수들은 초기화가 가능합니다.
2. ref에 저장한 값
3. 컴포넌트가 100번 렌디렁되면 -> ref에 저장된 값은 유지가 됩니다.
4. 따라서
a. state는 리렌더링이 꼭 필요한 값을 다룰 때 쓰면 된다.
b. ref는 리렌더링을 발생시키지 않는 값을 저장할 때 사용한다.
input
이 focusing
돼야 하는 등,DOM
요소를 핸들링해야 하는 순간이 나면 useRef
를 사용하는 것이 좋은 선택지가 됩니다.✨ 조금 더 깊은 활용도를 알아보자
위에서 설명드렸던 state
와 ref
의 차이점을 살펴보자
plusStateCountButtonHandler
와, plusRefCountButtonHandler
다르게 동작하는걸 확인해보자
state
는 변경되면 렌더링이 되고, ref
는 변경되면 렌더링이 되지 않습니다.
import "./App.css";
import { useRef, useState } from "react";
function App() {
const [count, setCount] = useState(0);
const countRef = useRef(0);
const plusStateCountButtonHandler = () => {
setCount(count + 1);
};
const plusRefCountButtonHandler = () => {
countRef.current++;
};
return (
<>
<div>
state 영역입니다. {count} <br />
<button onClick={plusStateCountButtonHandler}>state 증가</button>
</div>
<div>
ref 영역입니다. {countRef.current} <br />
<button onClick={plusRefCountButtonHandler}>ref 증가</button>
</div>
</>
);
}
export default App;
그러나 내부 변수는 let 키워드로 선언해서 변수 사용이 가능한가요?
let
키워드를 사용하게 되면 렌더링 시 어떻게 되냐면
다시 변수가 초기화 되는데 이유는 함수이기 때문입니다.
<input/>
태그에는 ref
라는 속성이 있는데,
이걸 통해 해당 DOM
요소로 접근이 가능합니다. 코드로 살펴보면
// 사용할 화면을 만들어주고
import "./App.css";
function App() {
return (
<>
<div>
아이디 : <input type="text" />
</div>
<div>
비밀번호 : <input type="password" />
</div>
</>
);
}
export default App;
여기서 화면이 렌더링 되고나서 아이디에 자동 포커싱 되게 할 수 없을까요?
// useRef 사용하여 포커싱 주기
import "./App.css";
function App() {
return (
<>
<div>
아이디 : <input type="text" />
</div>
<div>
비밀번호 : <input type="password" />
</div>
</>
);
}
export default App;
위에서 하면 화면이 렌더링 되자마자 바로 foucs
가 들어가진다.
그렇다면 아이디가 10자리 입력되면 자동으로
비밀번호 필드로 이동하도록 코드를 구현해보면
import { useEffect, useRef, useState } from "react";
import "./App.css";
function App() {
const idRef = useRef("");
const pwRef = useRef("");
const [id, setId] = useState("");
const onIdChangeHandler = (event) => {
setId(event.target.value);
};
// 렌더링이 될 때
useEffect(() => {
idRef.current.focus();
}, []);
// 왜 useEffect 안에 놓았을까요?
useEffect(() => {
if (id.length >= 10) {
pwRef.current.focus();
}
}, [id]);
return (
<>
<div>
아이디 :
<input
type="text"
ref={idRef}
value={id}
onChange={onIdChangeHandler}
/>
</div>
<div>
비밀번호 : <input type="password" ref={pwRef} />
</div>
</>
);
}
export default App;
그럼 여기서 id.length >= 10
이 로직을 useEffect
안에 왜 넣었을까?
당연히 우리가 아이디가 10자리 입력되면 자동으로 비밀번호 필드로 이동하도록
그러니 한번만 useEffect
를 사용하면 자동으로 넘어가지 않는다.
그래서 useEffect
에 id.length >= 10
으로 조건을 걸어서
id
의 길이가 10
과 같거나 넘으면 pwRef.current.focus();
가 실행되게 하는 것이다.