일반적인 React 데이터 플로우에서, 자식을 수정하려면 새로운 props를 전달하여 자식을 다시 렌더링해야 합니다. 그러나 일반적인 데이터 플로우에서 벗어나 직접적으로 자식을 수정해야 하는 경우 Ref를 사용합니다.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef(); //Ref는 React.createRef()를 통해 생성되고
}
render() {
return <div ref={this.myRef} />; //ref 어트리뷰트를 통해 React 엘리먼트에 부착됩니다.
}
}
const node = this.myRef.current;
//render 메서드 안에서 ref가 엘리먼트에게 전달되었을 때,
//그 노드를 향한 참조는 ref의 current 어트리뷰트에 담기게 됩니다.
React.createRef()로 생성된 ref의 current 프로퍼티 값은 ref를 전달받은 DOM 엘리먼트 입니다.
export class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef(); // ref 생성
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
this.textInput.current.focus();
} //DOM 노드를 얻기 위해 "current" 프로퍼티에 접근하고, DOM API를 사용하여 <input/> 엘리먼트에 포커스
render() {
//⭐생성자에서 생성한 `this.textInput` ref를 <input/> 엘리먼트와 연결
return (
<div>
<input type="text" ref={this.textInput} />
<input type="button" value="Focus the text input" onClick={this.focusTextInput} />
</div>
);
}
}
import { CustomTextInput } from "./CustomTextInput";
export class AutoFocusTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef(); //ref 생성
}
componentDidMount() {
this.textInput.current.focusTextInput();
} //CustomTextInput 컴포넌트의 인스턴스에 접근하여 focusTextInput 메서드를 호출
//CustomTextInput 컴포넌트의 인스턴스가 마운트 된 이후에 즉시 포커스
render() {
return <CustomTextInput ref={this.textInput} />;
} //⭐생성자에서 생성한 `this.textInput` ref로 CustomTextInput 컴포넌트의 인스턴스에 접근
}
주의!! 위 코드는 CustomTextInput가 클래스 컴포넌트일 때에만 작동합니다.
함수 컴포넌트는 인스턴스가 없기 때문에 함수 컴포넌트에 ref 어트리뷰트를 사용할 수 없습니다.
function MyFunctionComponent() {
return <input />;
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
render() {
// 이 코드는 동작하지 않습니다.
return (
<MyFunctionComponent ref={this.textInput} />
);
}
}
다만 함수컴포넌트 안에서 ref를 사용해서 DOM 엘리먼트나 클래스 컴포넌트의 인스턴스에 접근하는것은 가능합니다.
function CustomTextInput(props) {
const textInput = useRef(null); //ref생성
function handleClick() {
textInput.current.focus();
}
return ( //DOM 엘리먼트에 접근
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
ref를 설정하기 위한 또 다른 방법인 콜백 ref를 사용할 때에는 ref 어트리뷰트에 React.createRef()를 통해 생성된 ref를 전달하는 대신, 함수를 전달합니다.
전달된 함수는 컴포넌트의 인스턴스나 DOM 엘리먼트를 인자로서 받습니다.
export class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
//컴포넌트의 인스턴스가 마운트 될 때 ref 콜백을 DOM 엘리먼트와 함께 호출합니다.
this.setTextInputRef = (element) => {
this.textInput = element; //DOM 노드의 참조를 인스턴스의 프로퍼티에 저장
};
this.focusTextInput = () => {
if (this.textInput) this.textInput.focus();
};
}
componentDidMount() {
this.focusTextInput();
}
render() {
// text 타입의 input 엘리먼트의 참조를 인스턴스의 프로퍼티
// (예를 들어`this.textInput`)에 저장하기 위해 `ref` 콜백을 사용합니다.
return (
<div>
<input type="text" ref={this.setTextInputRef} />
<input type="button" value="Focus the text input" onClick={this.focusTextInput} />
</div>
);
}
}
//콜백 Ref도 다른 컴포넌트에 전달할 수 있습니다.
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}