Ref

JaeungE·2022년 1월 23일
0

React 찍어먹기

목록 보기
6/8
post-thumbnail

React의 데이터 흐름은 기본적으로 props를 통해 부모 컴포넌트가 자식에게 데이터를 전달하는 방식으로 진행된다.

이런 흐름에서 벗어나 자식 엘리먼트 혹은 컴포넌트에 직접 접근이 필요한 경우가 있는데, Ref 객체ref prop을 이용하면 자식의 참조를 전달받아 노드에 접근이 가능하다.

어떻게 사용하는지 아래에서 자세히 알아보자!





기본적인 Ref 사용방법

Ref를 사용하기 위해선 먼저 Ref 객체 생성이 필요하다.

React.createRef()

React.createRef() 메서드는 Ref 객체를 생성해서 반환한다.

Ref 객체를 생성했다면, 아래처럼 접근하려는 엘리먼트 혹은 컴포넌트의 ref propRef 객체를 부착하기만 하면 된다.


class App extends React.Component {
    constructor(props) {
        super(props);
        this.title = React.createRef();
    }

    render() {
        return (
            <h1 ref={this.title}>Hello World!</h1>
        );
    }
}

이제 App 컴포넌트는 this.title 프로퍼티를 이용해 노드에 접근이 가능해진다.

생명 주기(Lifecycle) 에서 도표를 보면 알 수 있듯이, ref 업데이트는 render()componentDidMount() 메서드 호출 사이에 완료된다.

그럼 정상적으로 노드에 접근한지 확인하기 위해 componentDidMount() 메서드 안에서 this.title 프로퍼티에 저장된 Ref 객체를 콘솔에 출력해보자.



위 코드를 통해 Ref 객체를 콘솔에 출력한 결과는 아래와 같다.



출력 결과를 보면 Ref 객체current 프로퍼티 안에 h1 엘리먼트가 담겨있는 것을 볼 수 있다.

즉, ref prop을 통해 넘겨받은 노드는 Ref 객체current 프로퍼티를 통해 접근이 가능하다.

여기까지 기본적인 Ref 사용방법이였다. 좀 더 자세한 내용은 아래에서 확인하자!




Ref.current

current 프로퍼티는 ref prop이 어디서 사용되었는지에 따라 다른 값을 가진다.

크게 HTML 엘리먼트, 클래스 컴포넌트, 함수 컴포넌트로 분류되는데, 어떤 값을 가지는지 자세히 알아보자.


HTML 엘리먼트

HTML 엘리먼트에서 사용되었다면, current 프로퍼티는 DOM Element를 참조한다.

버튼을 클릭하면 input element에 포커스를 하는 간단한 예제를 통해 확인하자.



버튼에 textFocus() 메서드를 이벤트 핸들러로 추가했다.

textFocus() 메서드는 ref로 참조하고 있는 DOM Elementfocus() 함수를 호출한다.



실행 결과는 위와 같다.



클래스 컴포넌트

ref prop클래스 컴포넌트에서 사용됐다면, current 프로퍼티는 Class의 인스턴스를 참조한다.

역시 간단한 예제를 통해 확인해보자.



App 컴포넌트는 MyComponent 컴포넌트를 호출할 때 ref prop으로 자신의 Ref 객체를 부착해서 호출하고 있다.

그러면 App 컴포넌트의 Ref.current 프로퍼티는 MyComponent 컴포넌트의 인스턴스를 참조하게 되고, App 컴포넌트에서 MyComponent 컴포넌트의 메서드 호출이 가능해진다.

App 컴포넌트에서 callRefMethod() 메서드를 이용해 activateAlert() 메서드를 호출하는 것을 볼 수 있는데, 실제로 작동하는지 한 번 확인해보자.



App 컴포넌트에서 MyComponent의 메서드 호출이 가능한 것을 볼 수 있다.



함수 컴포넌트

함수형 컴포넌트는 인스턴스가 존재하지 않기 때문에 ref prop을 이용한 참조가 불가능하다.

어디까지나 ref prop으로 함수형 컴포넌트를 참조하는 것이 불가능한 것이지, 함수형 컴포넌트에서 Ref 객체의 사용은 가능하기 때문에 헷갈리지 않도록 주의하자.




콜백 ref(callback ref)

callback refref가 설정되거나 혹은 해제될 때, 세부 사항을 구현하기 위해 사용한다.

기존의 ref와는 다르게 createRef() 메서드를 이용해 Ref 객체를 생성하지 않고도 참조가 가능하며, Ref 객체를 사용하는 것이 아니기 때문에 current 프로퍼티도 사용하지 않는다.

또한 ref prop에 등록된 callback ref는 컴포넌트가 마운트될 때, 인자로 엘리먼트 혹은 컴포넌트를 전달하고 마운트 해제시 인자로 null을 전달해서 호출한다.

그럼 간단한 예제를 통해 알아보자.



App 컴포넌트의 메서드 부터 차근차근 살펴보자.

setRef(node)
callback ref 메서드로, 인자로 전달된 node를 컴포넌트의 myRef에 대입하고, 마운트가 해제되어 nodenull로 호출하게 되면 alert() 함수를 호출한다.

focusInput()
이벤트 핸들러이며, myRef가 참조하고 있는 엘리먼트를 포커스 한다.

unmountComponent()
이벤트 핸들러이며, App 컴포넌트가 렌더링 되는 DOM 컨테이너에 다른 엘리먼트를 렌더링해서 App 컴포넌트를 마운트 해제 시키는 역할을 한다.

정리하면 Focus 버튼을 누르면 callback ref를 이용해 참조하고 있는 엘리먼트를 포커스 하고, Unmount 버튼을 누르면 App 컴포넌트의 마운트를 해제시킨다.

이제 결과를 확인해보자.



정상적으로 동작하는 것을 볼 수 있다.

이처럼 callback ref는 기존의 Ref와 다른점이 많으니 특징을 잘 기억해두자.




ref 전달하기(Forwarding Refs)

ref 전달하기는 단어 그대로 Ref 객체를 더 하위 트리에 있는 컴포넌트로 전달하는 방법이다.

React.forwardRef() 메서드를 이용해 Ref 객체를 전달할 수 있으며, 문법은 아래와 같다.

React.forwardRef(callback)

callback 함수의 내용은 다음과 같다.

(props, ref) => { ReactNode }

propsref 객체를 전달받고 ReactNode를 반환한다.

React.forwardRef(callback) 함수는 쉽게 말해 ref 전달이 가능한 컴포넌트를 생성한다.

간단한 예제를 보며 이해해보자.



Parent 컴포넌트에서 Ref 객체를 생성해서 Child 컴포넌트의 ref prop에 부착하였다.

Child가 보통의 클래스 컴포넌트라면 parentRef.current 프로퍼티는 Child 컴포넌트의 인스턴스를 가리켜야 하지만, 콘솔에 출력된 결과를 보면 다음과 같다.



Child 컴포넌트의 input element를 가리키는 것을 볼 수 있다.

이 말은 Parent 컴포넌트의 버튼을 클릭하면 Parent 컴포넌트의 자식인 Child 컴포넌트의 input element에 포커스가 가능하다는 얘기다.

정상적으로 동작하는지 직접 확인해보자.



의도한 대로 동작하는 것을 볼 수 있다.

이렇게 React.forwardRef() 메서드를 이용하면 Ref 객체를 트리 하부로 전달하는 것이 가능해진다.




ref 사용시 주의사항

current 유효성 검사

아래 예제처럼 조건부 렌더링을 사용할 때, Ref.current 프로퍼티가 참조하는 노드가 존재하지 않는 경우도 있다.



초기 상태는 상관 없지만, 만약 toggleFlag 버튼을 누른 뒤에 Focus 버튼을 누르면 에러가 발생할 수 있다.

그렇기 때문에 current 프로퍼티를 사용하는 함수는 아래처럼 유효성 검사를 진행하는 조건문을 넣어주자.





인라인 콜백 ref

callback ref 함수를 인라인으로 선언했다면 컴포넌트 업데이트가 이루어질 때, 처음엔 null을 인자로 하고 다음은 엘리먼트 혹은 컴포넌트를 인자로 해서 두 번 호출된다.

이유는 매 렌더링마다 새로운 callback 인스턴스가 생겨서 이를 초기화하기 위함인데, callback ref를 클래스에 메서드로 바인딩시켜서 해결할 수 있다.





참고 자료
Ref와 DOM - React
https://ko.reactjs.org/docs/refs-and-the-dom.html


Forwarding Refs - React
https://ko.reactjs.org/docs/forwarding-refs.html


React 최상위 API - React
https://ko.reactjs.org/docs/react-api.html

0개의 댓글