제어컴포넌트의 대안 방법으로 비제어 컴포넌트를 사용할 수 있습니다.
js에서 Input에 에 값을 변경하고 제어하는 방법으로 2가지가 있다고 했습니다.
비제어 컴포넌트는 DOM 자체에서 데이터를 다루게 됩니다.
하지만 form에 대한 구현은 제어 컴포넌트를 사용하는것이 좋습니다.
ref는 render 메서드에서 생성된 DOM 노드나 React 엘리먼트에 접근하는 방법을 제공합니다.
1. Focus, 텍스트 선택 영역을 관리할 때
2. 애니메이션을 직접적으로 실행시킬 때
3. 서드 파티 DOM 라이브러리를 사용할 때
리엑트에서는 가상돔을 사용하기에 js와 같이 selector를 사용하여 DOM에 접근할 수 없습니다.
함수형 컴포넌트에서 Ref를 사용하려면 훅 함수인 useRef를 사용해야합니다.
useRef로 선언한 변수를 제어하고자 하는 요소에 넣어 제어할 수 있습니다.
React
import React, { useRef } from "react";
const ref = useRef();
useEffect(() => {
// img DOM
console.log(ref.current)
},[])
// ...
<Img ref={ref} />
부모컴포넌트에서 자식 요소를 제어하려면 ref를 넘겨주어야합니다.
자기 자신의 컴포넌트는 ref를 통해 쉽게 제어가 가능합니다.
하지만 자식 컴포넌트의 제어는 ref를 넘겨준다고 동작하지 않습니다.
함수형에서는 forwordRef를 사용하라고 정의되어 있습니다.
React
import React from "react";
const Img = forwordRef((props, ref) => {
useEffect(() => {
// img DOM
console.log(ref.current)
},[])
// ...
<img ref={ref} />
});
💡 useImperativeHandle
- ref를 사용할 때 부모 컴포넌트에 노출되는 인스턴스 값을 사용자화합니다.
- forwordRef와 같이 많이 사용됩니다.
ref는 요소를 제어하는것 뿐만 아니라 state와 같이 상태를 저장할수 있습니다.
import React, { useRef } from "react";
const valueRef = useRef(1);
<button onClick={() => valueRef.current = valueRef.current + 1}>증가</button>
ref는 랜더링을 시키지 않는다고 했습니다. 하지만 useRef 대신 callback 함수를 넣어 변경할 수 있습니다.
// parent component
const [state, setState] = useState(0);
const callbackRef = (node) => {
if(node !== null){
setState(node.getBoundingCLientRect().height);
}
}
// ...
<div>상태값 : {state}</div>
<Img ref={callbackRef}/>
// children compoent
const Img = forwordRef((props, ref) => {
// ...
<img ref={ref} src=""/>
});
// children compoent
const [loading, setLoading] = useState(false);
const Img = forwordRef((props, ref) => {
// ...
<img
ref={loading ? ref : () => undefined}
onLoad={() => setLoading(true)}
src=""
/>
});