const refContainer = useRef(initialValue);
useRef는 .current 프로퍼티로 전달된 인자로 초기화된 변경 가능한 ref 객체를 반환합니다.
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>
</>
);
}
본질적으로 useRef는 .current 프로퍼티에 변경 가능한 값을 담고 있는 “상자”와 같습니다.
useRef는 매번 렌더링을 할 때 동일한 ref 객체를 제공하며, 내용이 변경될때 따로 알려주지 않습니다. .current 프로퍼티를 변형하더라도 리렌더링은 발생하지 않습니다.
HTML엘리먼트가 아닌 JSX에 refprop을 전달했을 때 자식이 ref를 받기 위해서 forwardRef가 사용됩니다.
아래의 예에서 FancyButton은 React.forwardRef를 사용하여 전달된 ref를 얻고, 그것을 렌더링 되는 DOM button으로 전달합니다.
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// 이제 DOM 버튼으로 ref를 작접 받을 수 있습니다.
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
이런 방법으로 FancyButton을 사용하는 컴포넌트들은 button DOM 노드에 대한 참조를 가져올 수 있고, 필요한 경우 DOM button을 직접 사용하는 것처럼 접근할 수 있습니다.
위의 예시에서 어떤 일이 일어나는지 단계별 설명
1. React.createRef를 호출해서 React ref를 생성하고 ref 변수에 할당합니다.
2. ref를 JSX 속성으로 지정해서 <FancyButton ref={ref}>로 전달합니다.
3. React는 이 ref를 forwardRef 내부의 (props, ref) => ... 함수의 두 번째 인자로 전달합니다.
4. 이 ref를 JSX 속성으로 지정해서 <button ref={ref}>으로 전달합니다.
5. ref가 첨부되면 ref.current는 <button> DOM 노드를 가리키게 됩니다.
useImperativeHandle(ref, createHandle, [deps])
useImperativeHandle은 ref를 사용할 때 부모 컴포넌트에 노출되는 인스턴스 값을 사용자화(customizes)합니다.
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
위의 예시에서
<FancyInput ref={inputRef} />
를 렌더링한 부모 컴포넌트는 inputRef.current.focus()를 호출할 수 있습니다.
import { forwardRef, useImperativeHandle, useState } from "react";
export default function Score({isStart}, ref){
const [score, setScore] = useState(0);
useImperativeHandle(ref, ()=>({
addScore: () => setScore(score => score = score + 100),
start: () => setScore(0)
}))
return(
<div>
{isStart ?
<h1>{score}</h1> :
<h1>점수 : {score}</h1>
}
</div>
)
}
Score = forwardRef(Score);
맨 하단의 Score = forwardRef(Score);를 통해 Score컴포넌트가 부모로 부터 ref를 받을 수 있게 되었다.
Score 컴포넌트의 useImperativeHandle메소드와 같이 부모 컴포넌트로부터 받은 ref를 첫 번째 prop으로 전달한 후 두 번째 prop으로 부모 컴포넌트에서 사용하고자 하는 함수를 위와같은 형식으로 작성해주면 된다.
부모 컴포넌트에서는 scoreRef.current.addScore();와 같은 식으로 사용하면 된다.