새로운 Reference 객체를 생성하는 기능이다.
const refObject = useRef()
refObject : 생성한 레퍼런스 객체는 컴퍼넌트 내부의 변수로써 일반적인 값들을 저장할 수 있다.
❗️ useState와 동일한가?
: 아니요! 컴포넌트 내부의 변수로 활용한다는 점을 똑같지만 useState는 값이 변경되면 컴포넌트가 리렌더링되지만 useRef는 어떤 경우에도 리렌더링되지않아요!
그래서 렌더링에 영향을 미치고 싶지않은 그러한 변수를 생성할 때 useRef를 사용하면 된다.
또한 useRef를 이용하면 컴포넌트가 렌더링하는 특정 DOM 요소에 접근할 수 있다. ( + 해당 요소 조작까지 가능)
Ex) 특정 요소에 포커를 준다, 해당 요소의 스타일을 갑자기 변경시킨다. 등을 구현할 수 있음
위의 내용을 이해하려면 직접 예시를 만들어봐야할 것 같다.
먼저 useRef를 선언해야한다.
Register.jsx
import { useRef } from "react";
Register.jsx
const refObj = useRef();
refObj를 콘솔에 찍어보면
refObj.current라고 적으면 된다.Register.jsx(초기값 0으로 설정)
const refObj = useRef(0);
console.log(refObj);
Register.jsx (return 문 안에 작성)
{/* useRef 사용해보기 */}
<button
onClick={() => {
refObj.current++;
console.log(refObj.current);
}}>
ref +1
</button>
💡 값을 출력하긴하지만 리렌더링을 유발시키지는 않는다.
그러면 onClick 핸들러만 계속 실행된다.
또한 console.log(refObj); 해당 콘솔 로그도 새로고침했을 때만 출력되고 버튼을 클릭했을 때 다시 출력되지않는다.
레퍼런스 객체는 우리 컴포넌트 내부에서 렌더링에 영향을 미치지않아야하는 그런 변수를 생성할 때 활용
Register.jsx(초기값 0으로 설정)
const counrRef = useRef(0);
const onChange = (e) =>{
counrRef.current++; ➡️ 변경할때마다 0인 current값 증가시키기
console.log(counrRef.current); ➡️ counrRef 객체의 값을 로그로 출력하기
setInput({
...input,
[e.target.name] : e.target.value,
})
}
Register.jsx (return 문 안에 작성)
<button onClick={onsubmit}>제출</button>
onsubmit 함수를 만들어야겠지?
Register.jsx
const inputRef = useRef(); ➡️ 레퍼런스 객체 생성해주고
const onsubmit = () =>{
// 이름을 정확히 입력했는지 확인
if(input.name === ""){
// 이름을 입력하는 DOM 요소에 포커스
console.log(inputRef.current);
inputRef.current.focus();
}
}
이름이 비어져있을 경우 해당 input 태그에 포커스가 가게끔 동작한다.
근데 폼에는 수많은 input 태그가 있는데 특정 input 태그라는 걸 알려면
input 태그 안에 ref 속성을 넣어주고 속성값으로 {inputRef} 을 넣어주면 된다.
inputRef.current에는 해당 DOM 요소가 출력된다.
import { useState, useRef } from "react";
// 간단한 회원가입 폼 만들기
// 1. 사용자의 이름 -> 사용자가 입력하는 이름을 State 로 보관
// 2. 생년월일
// 3. 국적
// 4. 자기소개
const Register = () =>{
const [input, setInput] = useState({
name:"",
birth:"",
country:"",
bio:""
})
const counrRef = useRef(0);
// const inputRef = useRef();
let count = 0;
const onChange = (e) =>{
// counrRef.current++;
// console.log(counrRef.current);
count++;
console.log(count);
setInput({
...input,
[e.target.name] : e.target.value,
})
}
const onsubmit = () =>{
// 이름을 정확히 입력했는지 확인
if(input.name === ""){
// 이름을 입력하는 DOM 요소에 포커스
console.log(inputRef.current);
inputRef.current.focus();
}
}
return (
<div>
{/* 이름 */}
<div>
<input
ref={inputRef}
name="name"
value={input.name}
onChange={onChange}
placeholder={"이름"}/>
</div>
{/* 생년월일 */}
<div>
<input
name="birth"
type="date"
value={input.birth}
onChange={onChange}/>
</div>
{/* 국적 */}
<div>
<select
name="country"
value={input.country}
onChange={onChange}>
<option>-</option>
<option>한국</option>
<option>미국</option>
<option>영국</option>
</select>
</div>
{/* 자기소개 */}
<div>
<textarea
name="bio"
value={input.bio}
onChange={onChange}/>
</div>
<button onClick={onsubmit}>제출</button>
</div>
)
};
export default Register;
❓ let count = 0;으로 만들어서 사용하면 안되나?
위의 코드를 let로 변수 선언하여 바꿔봤을 때 console.log(count) 하면 1 밖에 출력이 안된다.
➡️ 왜냐하면 OnChangeEvent 핸들러가 실행되면서 스테이트 값을 변경하는데 그러면 Register 컴포넌트가 리렌더링되면서 count가 0이되기 때문이다.
useRef나 useState를 이용해서 만든 리액트의 특수한 변수들은 컴퍼넌트가 리렌더링 된다고 해도 다시 리셋되지않는다.
➡️ 애초에 그렇게 설계되어있음