useRef란?
간단하게 말해서 .current 속성에 변경 가능한 값을 담고 있는 상자이다.
그래서 ref는 state와 비슷하게 어떤 값을 저장하는 저장 공간으로 사용될 수 있고 ref를 통해 DOM요소에 접근해서 여러 가지 일들을 할 수 있다.
useRef의 특성
1. useRef는 렌더링을 발생시키지 않는다.
State는 변경되면 자동으로 컴포넌트가 다시 랜더링이 된다. 하지만 Ref는 변경되어도 컴포넌트는 다시 렌더링 되지 않는다.
따라서 State 대신 Ref를 사용하면 불필요한 렌더링을 막을 수 있다.
2. 컴포넌트가 렌더링이 되어도 Ref 안에 저장되어 있는 값은 변화되지 않고 그대로 유지가 된다.
변화는 감지해야 하지만 그 변화가 렌더링을 발생시키면 안 되는 값을 다룰 때 유용하게 사용할 수 있다.
어떤 값을 저장하는 저장 공간으로 사용할 때
const countRef = useRef(0);
<button onClick={()=>countRef.current +=1;}>Ref Count</button>
1. State와 Ref의 차이
import { useState,useRef } from "react";
const App = () => {
const [count, setCount] = useState(0);
const countRef = useRef(0);
console.log("렌더링")
return (
<div style={{padding : 20}}>
<p>State : {count}</p>
<p>Ref : {countRef.current}</p>
<button onClick={()=>setCount(count+1)}>State Count</button>
<button onClick={()=>{countRef.current +=1; console.log("Ref : ", countRef.current);}}>Ref Count</button>
</div>
);
}
export default App;
결과
처음 Mount 될 때 한번 렌더링 되었다.
count State를 버튼으로 값을 5번 변경하였더니 5번 렌더링이 되었다.
Ref Count 버튼을 5번 눌렀으나 화면에 렌더링 되지 않지만 콘솔창을 통해 Ref의 current 값이 올라가고 있다는 것을 알 수 있다.
그러고 나서 State Count 버튼을 눌러서 count 값을 변화시켜 렌더링을 하였더니 Ref의 current 값도 같이 화면에 업데이트되었다.
이를 통해 알 수 있는 Ref의 장점
자주 바뀌는 값을 State에 넣어두면 바뀔 때마다 계속 렌더링이 되어서 성능이 떨어질 수 있다.
이때 Ref를 사용하면 값이 바뀌어도 렌더링이 발생하지 않아서 성능이 향상될 수 있다.
2. 컴포넌트 내부의 변수와 Ref의 차이
변수와 Ref 둘 다 렌더링을 발생시키지 않아서 화면이 업데이트되지 않는다.
이때 컴포넌트가 렌더링이 된다는 것은 컴포넌트를 나타내는 함수가 다시 불린다는 뜻이다.
함수가 다시 불리면 불릴 때마다 함수 내부에 있는 변수들이 다시 초기화가 된다.
따라서 컴포넌트 내부의 변수는 렌더링이 발생하면 초기화가 된다.
하지만 Ref는 컴포넌트가 렌더링이 되어도 계속 값을 유지한다.
왜냐하면 Ref의 값은 컴포넌트의 전 생애주기를 통해 유지가 되기 때문이다.
즉, 컴포넌트가 브라우저에 Mount 된 시점부터 Unmout 될 때까지 값을 계속 유지할 수 있다.
import { useState,useRef } from "react";
const App = () => {
const [render, setRender] = useState(0);
const countRef = useRef(0);
let count = 0;
return (
<div style={{padding : 20}}>
<p>Ref : {countRef.current}</p>
<p>Var : {count}</p>
<button onClick={()=>{countRef.current +=1; console.log("Ref : ", countRef.current);}}>Ref Count</button>
<button onClick={()=>{count +=1; console.log("변수 : ", count);}}>변수 Count</button>
<button onClick={()=>setRender(render+1)}>렌더링</button>
</div>
);
}
export default App;
결과
Ref를 사용한 count & 변수를 사용한 count 둘 다 4번씩 누른 후 렌더링 버튼을 눌러 렌더링을 발생시켰다.
Ref를 사용한 count의 값은 화면에 업데이트가 되었지만 내부에 있는 변수는 업데이트가 되지 않았다.
렌더링을 발생시킨 후 다시 Ref를 사용한 count를 누르면 바로 4 다음부터 5,6 count 하지만 변수를 사용한 count를 누르면 다시 초기값인 1부터 count 한다.
따라서 렌더링이 발생하면 컴포넌트 내부의 변수의 값은 초기화가 되지만 Ref의 값은 유지가 된다는 것을 알 수 있다.
DOM 요소에 접근
const ref = useRef(value)
<input ref={ref}/>
useRef를 부르면 ref를 반환한다. ref를 접근하고자 하는 요소의 태그에 ref 속성으로 넣으면 해당 요소에 접근할 수 있다.
대표적으로 회원가입을 할 때 입력하지 않은 정보가 있을 때 focus를 주는 작업에서 사용된다.
import { useRef } from "react";
const App = () => {
const nameRef = useRef();
const handleClick = () => {
if(nameRef.current.value.length < 1){
nameRef.current.focus()
}
};
return (
<div style={{padding : 20}}>
<input ref={nameRef} placeholder="이름을 입력하세요"/>
<button onClick={handleClick}>입력</button>
</div>
);
}
export default App;
이름의 현재값 길이가 1보다 작으면 즉 입력하지 않았으면 input창을 focus 하는 코드이다.
결과
이름을 입력하지 않고 입력을 눌렀을 때 focus 된 모습이다.
이름을 입력 후에 입력을 눌렀을 때는 focus 되지 않는다.