[React] Ref와 DOM

파송송계란빡 ㅣ 2022. 6. 20. 14:50

Ref

Ref는 render 메서드에서 생성된 DOM 노드나 React 엘리먼트에 접근하는 방법

 

Ref를 사용해야 하는 경우

  • 포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때.
  • 애니메이션을 직접적으로 실행시킬 때.
  • 서드 파티 DOM 라이브러리를 React와 같이 사용할 때.

포커스 유지

/*SimpleForm.js*/
import React, { useRef } from "react"

//ref를 활용 -> 비제어 컴포넌트 방식으로 form을 다뤄보자
export default function UnControlledForm() {
    const inputRef = useRef()

    const handleSubmit = (e) => {
        e.preventDefault()
        alert(inputRef.current.value)
        inputRef.current.focus()
    }

    return (
        <form onSubmit={handleSubmit}>
            <label>닉네임 : </label>
            <input type="text" name="nickname" ref={inputRef}></input>
            <input type="submit" value="제출"></input>
        </form>
    )
}

ref 생성

import React, { useRef } from "react"

export default function UnControlledForm() {
    const inputRef = useRef()

return (
        <div ref={inputRef}></div>
    )
}
  • ref가 엘리먼트에게 전달되었을 때, 그 노드를 향한 참조는 ref의 current어트리뷰트에 담기게 됨
  • ref 어트리뷰트가 HTML 엘리먼트에 쓰였다면, ref는 자신을 전달받은 DOM 엘리먼트를 current 프로퍼티의 값으로서 받음
  • ref 어트리뷰트가 커스텀 클래스 컴포넌트에 쓰였다면, ref 객체는 마운트된 컴포넌트의 인스턴스를 current 프로퍼티의 값으로서 받습니다.
  • 함수 컴포넌트는 인스턴스가 없기 때문에 함수 컴포넌트에 ref 어트리뷰트를 사용할 수 없습니다.

ref forwarding

ref forwarding

  • 부모 컴포넌트가 자식 컴포넌트의 ref를 자신의 ref로서 관리 함
  • 자식 컴포넌트의 DOM 노드를 부모 컴포넌트에게 공개하는 방법

 

ref forwarding

  • CarPatent 컴포넌트가 자식 Cat 컴포넌트에서 만든 img 태그를 관리할 수 있음
  • CatParent에서 만든 ref 객체를 가지고, 자식 컴포넌트에 넘겨 줌

→ ref={carRef}

/*CatParent.js*/
import React, { useRef } from "react";
import Cat from "./Cat";

// Cat 안에 있는 image 사이즈를 알고싶다.
export default function CatParent() {
    const catRef = useRef()

    console.log("부모 컴포넌트 CatParent");
    console.log(catRef)

    return (
        <div>
            <h4> 고양이가 세상을 구한다 ️</h4>
            <div>
                <Cat a={"a"} ref={catRef} />
            </div>
        </div>
    );
}
  • 자식 컴포넌트인 Cat.js는 자신이 갖고 있는 img 태그에 ref를 붙였음
/*Cat.js*/
import React, { forwardRef } from "react";

const Cat = **forwardRef((props, ref)** => {
    console.log("자식 컴포넌트 Cat");
    console.log(ref)

    return (
        <div>
            <img
                src="https://static01.nyt.com/images/2016/03/30/universal/ko/well_cat-korean/well_cat-superJumbo-v2.jpg?quality=90&auto=webp"
                alt="cat"
                style={{ width: "150px" }}
                ref={ref}
            ></img>
        </div>
    );
});

export default Cat;

 

  • useEffect를 이용해서 렌더링 한번 해준 후

→ current에 img가 들어감

  • uesEffect에서 변화가 ref 객체에 변화가 생겨 undefined였다가 ref.current에 img를 갖게 되는것은 부모 컴포넌트인 Catpaent 컴포넌트는 알지 못함
/*Cat.js*/
import React, { forwardRef, useEffect } from "react";

const Cat = forwardRef((props, ref) => {
    console.log("자식 컴포넌트 Cat");
    console.log(ref)

    useEffect(() => {
        console.log("useEffect in Cat")
        console.log(ref)
    }, [])

    return (
        <div>
            <img
                src="https://static01.nyt.com/images/2016/03/30/universal/ko/well_cat-korean/well_cat-superJumbo-v2.jpg?quality=90&auto=webp"
                alt="cat"
                style={{ width: "150px" }}
                ref={ref}
            ></img>
        </div>
    );
});

export default Cat;

 

ref forwarding

  • 부모에서 자식에 있는 img의 사이즈를 알 수 있음
/*CatParent.js*/
import React, { useRef } from "react";
import Cat from "./Cat";

// Cat 안에 있는 image 사이즈를 알고싶다.
export default function CatParent() {
    const catRef = useRef()

    console.log("부모 컴포넌트 CatParent");
    console.log(catRef)

    return (
        <div>
            <h4> 고양이가 세상을 구한다 ️</h4>
            <div>
                <Cat a={"a"} ref={catRef} />
                <button onClick={() => alert(catRef.current.height)}>고양이의 크기를 알고싶어</button>
            </div>
        </div>
    );
}
/*Cat.js*/
import React, { forwardRef, useEffect } from "react";

const Cat = forwardRef((props, ref) => {
    console.log("자식 컴포넌트 Cat");
    console.log(ref)

    useEffect(() => {
        console.log("useEffect in Cat")
        console.log(ref)
    }, [])

    return (
        <div>
            <img
                src="https://static01.nyt.com/images/2016/03/30/universal/ko/well_cat-korean/well_cat-superJumbo-v2.jpg?quality=90&auto=webp"
                alt="cat"
                style={{ width: "150px" }}
                ref={ref}
            ></img>
        </div>
    );
});

export default Cat;

[React] Ref와 DOM