ref란 React에서 DOM 노드나 React 엘리먼트에 직접 접근할 수 있도록 하는 것이다.
ref 객체는 현재 프로퍼티가 변경할 수 있고 어떤 값이든 보유할 수 있는 일반 컨테이너이다.
이는 class의 인스턴스 프로퍼티와 유사하다.
useState()는 state가 변경되면 re-rendering을 발생시키지만,
useRef()는 .current가 변경되어도 re-rendering을 발생시키지 않는다.
re-rendering을 발생시킬 필요는 없지만 상태관리를 해야 될 때 useRef()를 유용하게 쓸 수 있다.
Ref 사용 사례
대부분 경우에 폼을 구현하는데 제어 컴포넌트를 사용하는 것이 좋다.
제어 컴포넌트에서 폼 데이터는 React 컴포넌트에서 다루지만,
대안인 비제어 컴포넌트는 DOM 자체에서 폼 데이터가 다루어지며 DOM에서 폼 데이터를 가져오기 위해서는 ref를 사용해야 한다.
import에 { useRef }
추가
import { useRef } from 'react';
useRef() 변수 선언
const inputRef = useRef();
값을 받을 엘리먼트의 ref 속성 값에 useRef의 객체로 설정
useRef()의 객체 안에는 current라는 키가 자동으로 들어있으며 current에 값을 받을 엘리먼트가 들어가게 된다
export default function UnControlledForm(){
const inputRef = useRef();
function handleSubmit(e){
e.preventDefault();
alert(inputRef.current.value)
}
return(
<form onSubmit={handleSubmit}>
<label>닉네임 : </label>
<input type="text" name="nickname" ref={inputRef} />
<input type="submit" />
</form>
);
}
import에 { createRef }
추가
import { createRef } from 'react';
createRef() 변수 선언
this.myRef = React.createRef();
값을 받을 엘리먼트의 ref 속성 값에 createRef 설정
createRef()의 객체 안에는 current라는 키가 자동으로 들어있으며 current에 값을 받을 엘리먼트가 들어가게 된다
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
부모 컴포넌트가 자식 컴포넌트의 Ref를 전달받으려면 자식 컴포넌트가 클래스 컴포넌트일 때에만 작동하며, 자식 컴포넌트가 함수 컴포넌트일 때는 React 16.3 이후 버전의 Forwarding Refs를 사용해야 한다.
Forwarding Refs는 부모 컴포넌트가 자식 컴포넌트의 ref를 자신의 ref로써 관리할 수 있다.
부모 컴포넌트의 import에 { useRef }
추가 후 useRef() 변수 선언
import React, { useRef } from 'react';
export default function ParentCompnt() {
const catRef = useRef();
return (
<ChildrenCompnt a={"a"} ref={catRef} />
);
}
자식 컴포넌트의 import에 { forwardRef }
추가
import React, { forwardRef } from "react";
인자(props, ref)를 받아 forwardRef() 로 감싼다.
const ChildrenCompnt = forwardRef((props, ref) => {
return (
<div>
<img
src="ghibli.png"
alt="welcome Ghibli"
style={{ width: "150px" }}
></img>
</div>
);
});
값을 받을 엘리먼트의 ref 속성 값에 useRef의 객체로 설정
const ChildrenCompnt = forwardRef((props, ref) => {
return (
<div>
<img
src="ghibli.png"
alt="welcome Ghibli"
style={{ width: "150px" }}
/* ↓ 이부분 */
ref={ref}
></img>
</div>
);
});
useRef()는 re-rendering을 발생시키지 않기 때문에
Forwarding Refs 문법을 사용하여 부모 컴포넌트가 자식 컴포넌트의 ref를 자신의 ref로써 관리 할 때에도 .current가 변경됨을 알지 못 한다.
때문에 Callback ref 즉, ref 에 useRef로 반환된 값을 넘기는게 아니라 함수를 넘겨 사용하면 re-rendering을 발생시켜 .current가 변경됨을 알 수 있다.
import React, { useRef, useState } from 'react';
export default function ParentCompnt() {
const [height, setHeight] = useState(1);
const catCallbackRef = (node) => {
if(node !== null){
setHeight(node.getBoundingClientRect().height)
}
}
return (
<ChildrenCompnt ref={catCallbackRef} />
);
}