- useRef
- useRef 사용 목적
- useRef를 이용한 저장 공간 생성
- useRef를 이용한 DOM 요소 접근
- useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
- Note that
useRef()
is useful for more than theref
attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.
initialValue
을 받아 MutableRefObject
를 반환javascript Object
라는 의미
- convenience overload for refs given as a ref prop as they typically start with a null value
useRef
returns a mutable ref object whose.current
property is initialized to the passed argument (initialValue
).- Usage note: if you need the result of useRef to be directly mutable, include
| null
in the type of the generic argument.
지네릭으로 null이외에 다른 타입을 넘겨줄 경우 변경이 가능
(앞에 적어놓은 공식문서 설명의 2번째 부분
)
- useRef는 3가지의 call signature를 제공
- null이 들어갈 경우 readonly인 RefObject를 반환 하며 current 프로퍼티의 변경이 불가능하지만 지네릭으로 따로 설정할 경우 변경 가능
- 그 외의 경우 MutableRefObject를 반환하며 변경이 가능
- 반환된 object는 컴포넌트의 모든 라이프 사이클 동안 유지됨
import { useRef } from "react";
function App() {
const countRef = useRef(0);
const handleRefIncrease = () => {
countRef.current += 1;
console.log(countRef);
}
return (
<>
{countRef.current}
<button onClick={handleRefIncrease}>Ref</button>
</>
);
}
export default App;
재 렌더링을 발생시키지 않기 때문
변경 가능한 값을 담고 있는 상자
와 같음컴포넌트 내의 변수 값을 조회, 수정하는 방법으로도 사용
이 가능import { MutableRefObject, useRef } from "react";
function App() {
const inputRef = useRef<HTMLInputElement>();
console.log(inputRef);
return (
<>
<input ref={inputRef as MutableRefObject<HTMLInputElement>} type="text" placeholder="username"/>
</>
);
}
export default App;
app.tsx
import { MutableRefObject, useRef } from "react";
function App() {
const inputRef = useRef<HTMLInputElement>();
const handleUserAuth = () => {
let user = inputRef.current?.value as string;
alert(`환영합니다. ${user}님`)
inputRef.current?.focus();
}
return (
<>
<input ref={inputRef as MutableRefObject<HTMLInputElement>} type="text" placeholder="username"/>
<button onClick={handleUserAuth}>login</button>
</>
);
}
export default App;
import { useEffect, useRef, useState } from "react";
function App() {
useEffect(() => {
console.log("컴포넌트 재 렌더링 중");
})
const countRef = useRef(0);
const [count, setCount] = useState(0);
const handleCountIncrease = () => {
setCount(count + 1);
}
const handleRefIncrease = () => {
countRef.current += 1;
console.log(countRef)
}
return (
<>
{countRef.current}
<button onClick={handleRefIncrease}>Ref</button>
{count}
<button onClick={handleCountIncrease}>count</button>
</>
);
}
export default App;
In a controlled component, form data is handled by a React component.
The alternative is uncontrolled components, where form data is handled by the DOM itself.
대부분 경우에
폼을 구현하는데 제어 컴포넌트를 사용하는 것이 좋습니다.
제어 컴포넌트에서 폼 데이터는 React 컴포넌트에서 다루어집니다. 대안인비제어 컴포넌트는 DOM 자체에서 폼 데이터가 다루어집니다.
- HTML에서
input, textarea, select
와 같은 폼 엘리먼트는 일반적으로 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트합니다. React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState()에 의해 업데이트됩니다.- 우리는 React state를 “신뢰 가능한 단일 출처 (single source of truth)“로 만들어 두 요소를 결합할 수 있습니다. 그러면 폼을 렌더링하는 React 컴포넌트는 폼에 발생하는 사용자 입력값을 제어합니다. 이러한 방식으로 React에 의해 값이 제어되는 입력 폼 엘리먼트를 “제어 컴포넌트 (controlled component)“라고 합니다.
export default function App() {
const [input, setInput] = useState("");
const onChange = (e) => {
setInput(e.target.value);
};
return (
<div className="App">
<input onChange={onChange} />
</div>
);
}
event 객체를 이용해 setState()로 값을 저장
하는 방식사용자가 입력한 값과 저장되는 값이 실시간으로 동기화
비제어 컴포넌트 방식을 사용할 땐, 제어 컴포넌트 방식에서 사용한 setState()를 쓰지 않고 ref를 사용해서 값을 얻음
xport default function App() {
const inputRef = useRef(); // ref 사용
const onClick = () => {
console.log(inputRef.current.value);
};
return (
<div className="App">
<input ref={inputRef} />
<button type="submit" onClick={onClick}>
전송
</button>
</div>
);
}
- 제어 컴포넌트의 경우 사용자가 입력을 하는 액션을 취할때마다 재 렌더링을 발생시킴
- 반면, 비제어 컴포넌트는 사용자가 직접 트리거 하기 전까지는 재 렌더링을 발생시키지도 않고 값을 동기화 시키지도 않음
- useRef는 힙 영역에 저장되는 일반적인 자바스크립트 객체
- 매번 렌더링할 때 동일한 객체를 제공한다. heap에 저장되어 있기 때문에 어플리케이션이 종료되거나 가비지 컬렉팅될 때 까지, 참조할때마다 같은 메모리 값을 가짐
- 즉, 값이 변경되어도 리렌더링이 되지 않는데 그 이유는 같은 메모리 주소를 갖고있기 때문에 자바스크립트의 === 연산이 항상 true 를 반환
- 변경사항을 감지할 수 없어서 리렌더링을 하지 않는다는 뜻
대부분 경우에 폼을 구현하는데 제어 컴포넌트를 사용하는 것이 좋습니다. 제어 컴포넌트에서 폼 데이터는 React 컴포넌트에서 다루어집니다. 대안인 비제어 컴포넌트는 DOM 자체에서 폼 데이터가 다루어집니다.
비제어 컴포넌트를 사용해 렌더링을 최적화 하는 라이브러리
react-hook-form
별코딩님 - useRef
https://www.youtube.com/watch?v=EMK8oUUwP5Q
hyunjine - useState vs useRef
https://velog.io/@hyunjine/useState-vs-useRef
yukyung - React: 제어 컴포넌트와 비제어 컴포넌트의 차이점