ref는 특정 컴포넌트에 접근하는데 사용된다
ref에 관한 수많은 블로그 글을 보았고, 강의도 들었지만 정확한 개념이 잘 이해되지 않는다…(좀 추상적?)
목표는 ref가 정확이 무엇인지, prop과 state와의 명확한 차이점이 무엇인지, state와의 차이점은 무엇인지, 왜 남용하면 안되는지를 파악하는 것이다.
일반적으로 부모 자식 컴포넌트 간에 props로 상호작용한다
자식을 수정하려면 새로운 props를 전달하여 다시 렌더링해야한다 →
따라서 React 만으로 DOM을 조작하기 어려울 때 사용한다
그러나, 일반적인 데이터 플로우에서 벗어나
직접적으로 자식을 수정해야 하는 경우도 가끔씩 있다.
예를 들면 vanilla js에서 DOM을 조작하려면 선택자를 이용한다
const myElement = document.querySelector('#my-id');
myElement.style.color = 'red';
하지만 React에서 DOM을 직접 수정하려면 ref를 사용한다.
저장공간
state변화 → 렌더링 → 컴포넌트 내부 변수들 초기화
ref의 변화 → no 렌더링 → 변수들 값 유지, state값이 변화해도 ref의 값은 유지됨
DOM 요소에 접근
input요소 등에 접근이 용이
document.querySelector와 비슷한 역할을 한다
즉 state만으로 해결할 수 없는 기능
DOM에 접근해야 할 때 ref를 사용한다.
왜냐하면 useState로 생성한 변수가 아닌 이상, 다른 변수들이 변경되더라도 컴포넌트가 리렌더링 되지 않기 때문이다.
state로만 해결할 수 없고, “DOM을 반드시 직접 건드려야 할 때!!!” 사용된다
ref는 render 메서드에서 생성된 DOM 노드나 React 엘리먼트에 접근하는 방법을 제공합니다. - 공식문서
reference를 의미한다 - 참조
useRef 라는 Hook API를 이용한다
import { useRef } from 'react'
const refContainer = useRef(initialValue);
useRef를 사용해서 렌더링에 관여하지 않는 변수를 만든다
(렌더링을 발생시키지 않고 렌더링을 해도 남아있는)
그리고 이것은 전역적으로 작동하지 않고 내부에서만 작동한다.
useRef로 선언한 객체는 컴포넌트와 생애주기를 함께한다??? → (생애주기는 다음에..)
useRef는엘리먼트 ref용 값을 선언할 때 사용하는 Hook
but 함수를 재호출하더라도 생애주기(lifecycle) 동안은 current를 유지한다
useRef로 생성된 객체 refContainer 는 current값이 변화해도 렌더링에 관여하지 않는다.
그 이유는…? useRef()가 순수 자바스크립트 객체를 생성하기 때문!!!
inputRef.current.value = 'some value';
여기서 state를 업데이트 하지 않는다 → 렌더링 하지 않는다.
ref 안의 current에 저장된다
컴포넌트가 렌더링되어도 언마운트되기 전에는 값이 유지된다.
function App() {
const [name, setName] = useState('');
const prevName = useRef('');
// prevName is just object current property -> prevName.current
useEffect(() => {
prevName.current = name;
}, [name]);
// using ref => we don't actually need so
// 필요하지 않다면 렌더링을 일으키지 않음...
// 리렌더링하지 않고 DOM에 접근, 값 유지
return (
<>
<input value={name} onChange={event => setName(event.target.value)} />
<div>
My name is {name} and it used to be {prevName.current}
</div>
</>
);
}
const prevName = useRef('');
useRef를 통해 생성된 객체 prevName → 컴퍼넌트가 변경되어 렌더링할때마다 객체의 current 프로퍼티가 컴포넌트의 DOM 객체로 설정됨.
React는 노드가 변경될 때마다 변경된 DOM 노드에 그것의 .current 프로퍼티를 설정함
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
Ref는 state와는 다르게 값이 바뀌어도 다시 렌더링을 일으키지 않는다
const renderCount = useRef(0);
useEffect(() => {
renderCount.current = renderCount.current + 1;
});
return (
<>
<input value={name} onChange={event => setName(event.target.value)} />
<div>My name is {name}</div>
<div>I rendered {renderCount.current} times</div>
</>