-
1-5 React Hooks - useRefReact 숙련주차 2023. 4. 30. 17:44
useRef
ref는 reference를 의미한다. 참조라는 뜻을 가진다.
useRef 활용방법
1. 저장공간
2. DOM요소 접근
1. useRef hook소개
(어딘가에 저장한)DOM요소에 접근할 수 있도록 하는 React Hook.
HTML과 JavaScript를 사용할때 특정DOM을 선택하기위해 사용했던 방법
//(1)getElemtById 이용
const divTag = document.getElementById('#myDiv');
//(2)querySelector 이용
const divTag2 = document.querySelector('#myDiv');
리액트에서도 Dom을 선택해야할 상황이 생기기 마련이다. 예를들면 화면이 렌더링되자마자
특정 input태그가 focusing이 돼야하는 경우(네이버 들어가면 검색 인풋창에 커서가 깜빡이고 있는상태)가 그것이다.
그럴 경우 useRef hook을 사용한다.
2. useRef hook 사용방법import { useRef } from "react"; import "./App.css"; function App() { const ref = useRef("초기값"); console.log("ref", ref); ref.current = "변경값"; console.log("ref2", ref); return <div>App</div>; } export default App;
변수 설정하듯이 const ref = useRef("초기값");의 형태를 만든다.
ref의 형태를 console창에 찍어보면 객체형태로 나오는것을 볼 수 있고,
그 ref의 current를 ref.current = "변경값";의 형태로 바꾸고 ref를 다시 찍어보면,
객체형태로 {current: '변경값'}으로 바뀐것을 볼 수 있다.
(중요) 이렇게 설정된 ref값은 컴포넌트가 계속해서 렌더링 되어도 unmount전까지 값을 유지한다.
이러한 특징 때문에 useRef는두가지 용도로 사용된다.
1. 저장공간
a. state와 비슷한 역할을 한다. 하지만 state는 변화가 일어나면 다시 렌더링이 일어난다(이유: 함수형 컴포넌트이기 때문에 함수가 다시 그려진다). 내부 변수들은 초기화된다.
b. ref에 저장한 값은 렌더링을 일으키지 않는다. 즉, ref의 값 변화가 일어나도 렌더링으로 인해 내부 변수들이 초기화되는것을 막을 수 있다.
c. 컴포넌트가 100번 렌더링→ref에 저장한 값은 유지된다.
d. 정리하면
i. state는 리렌더링이 꼭 필요한 값을 다룰 때 사용한다.
ii. ref는 리렌더링을 발생시키지 않는 값을 저장할 때 사용한다.
2. DOM
a. 렌더링 되자마자 특정 input이 focusing되어야한다면 uesRef를 사용한다.
예제코드로 특징 살펴보기
state와 ref의 차이점import { useRef, useState } from "react"; import "./App.css"; function App() { const [count, setCount] = useState(0); const countRef = useRef(0); const plusStateCountButtonHandler = () => { setCount(count + 1); }; const plusRefCountButtonHandler = () => { countRef.current++; console.log(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;
DOM에 접근하는 useRef(아까말한 네이버 인풋창 포커싱처럼)
아이디인풋과 패스워드인풋을 만들어놓고, 아이디 인풋창에 포커싱 되도록 해보자.
일단 화면이 처음 렌더링 될때 어떤 작업을 하는 useEffect를 만들도록 한다.
dependency array도 일단 빈 배열로 같이 넣는다.
그리고 jsx문법이 들어가는 곳에 idRef라는 상수를 useRef('')로 선언한 후
포커싱 되게 하고싶은 input태그안에 ref={idRef}를 넣어서 연결시켜준다.
그리고 useEffect함수안에 idRef.current.focus();를 해주면 비로소 아이디 인풋창에 포커싱이 된다.import { useEffect, useRef } from "react"; import "./App.css"; function App() { const idRef = useRef(""); //화면이 렌더링 될 때, 어떤 작업을 하고싶다면 useEffect useEffect(() => { idRef.current.focus(); }, []); return ( <> <div> 아이디 : <input type="text" ref={idRef} /> </div> <div> 패스워드 : <input type="password" /> </div> </> ); } export default App;
미션
위 코드에서 아이디가 열자리 입력되면 자동으로 패스워드 필드로 이동하도록 코드짜기
1. 아이디가 10자리가 입력되는지 트래킹하는 요소를 넣어야한다. useState이용
const [id, setId] = useState('');선언하고
아래 아이디인풋태그안에 value={id} onChange={(event)=>{setId(event.target.value)}}를 추가해준다.
이렇게하면 아이디인풋창안에 타이핑 하나하나할때마다 페이지에 문자가 적히는데 이걸 렌더링이된다라고 한다.
2. 인풋창에 열자리가 입력될때 패스워드인풋창으로 포커싱하는 작업을 하기 위해
useEffect(()=>{}, [])를 하나 더 선언한다.useEffect(() => { if(id.length >= 10){ pwRef.current.focus(); } }, [id]);
만약 id의 길이가 10보다 크거나 같을때 패스워드인풋창으로 포커싱해주는데,
useEffect는 id라는 state가 바뀔때마다 발동되어야하기때문에 dependency array안에도 id를 넣어줘야만한다.이렇게 저장하고 페이지에서 아이디인풋창에 열자리를 타이핑해보면 패스워드인풋창으로 포커싱되는것을 볼 수 있다.
import { useEffect, useRef, useState } from "react"; import "./App.css"; function App() { const idRef = useRef(""); const pwRef = useRef(""); const [id, setId] = useState(""); //화면이 렌더링 될 때, 어떤 작업을 하고싶다면 useEffect useEffect(() => { idRef.current.focus(); }, []); useEffect(() => { if (id.length >= 10) { pwRef.current.focus(); } }, [id]); return ( <> <div> 아이디 :{" "} <input value={id} onChange={(event) => { setId(event.target.value); }} type="text" ref={idRef} /> </div> <div> 패스워드 : <input type="password" ref={pwRef} /> </div> </> ); } export default App;
단순하게 생각해서 useEffect대신에 onChange를 이용해서 input태그안에
if()문을 넣어서 할수있지않을까 하는 생각이 들 수도 있다.import { useEffect, useRef, useState } from "react"; import "./App.css"; function App() { const idRef = useRef(""); const pwRef = useRef(""); const [id, setId] = useState(""); useEffect(() => { idRef.current.focus(); }, []); return ( <> <div> 아이디 :{" "} <input value={id} onChange={(event) => { setId(event.target.value); if(id.length >=10) { pwRef.current.focus(); } }} type="text" ref={idRef} /> </div> <div> 패스워드 : <input type="password" ref={pwRef} /> </div> </> ); } export default App;
하지만 이렇게 하면 열한자리를 입력해야 아래로 포커싱되는것을 볼 수 있다.
그 이유는 리액트는 state를 배치업데이트방식으로 적용했다.
그래서setId에서 state를 set한것이 if문안에서 아직 반영이 안되기때문에 id.length값이 한박자 늦게 들어오게된다.⭐state는 배치업데이트방식이다⭐
'React 숙련주차' 카테고리의 다른 글
1-7 React Hooks - React.memo (1) 2023.05.02 1-6 React Hooks - useContext (0) 2023.04.30 1-4 React Hooks - useEffect (0) 2023.04.30 1-3 React Hooks - useState (0) 2023.04.29 1-2 Styled Components (전역 스타일링) (0) 2023.04.29