React Ref와 비제어 컴포넌트

YEZI🎐·2022년 6월 29일
0

React

목록 보기
17/29

Ref

ref란 React에서 DOM 노드나 React 엘리먼트에 직접 접근할 수 있도록 하는 것이다.
ref 객체는 현재 프로퍼티가 변경할 수 있고 어떤 값이든 보유할 수 있는 일반 컨테이너이다.
이는 class의 인스턴스 프로퍼티와 유사하다.

useState()는 state가 변경되면 re-rendering을 발생시키지만,
useRef()는 .current가 변경되어도 re-rendering을 발생시키지 않는다.
re-rendering을 발생시킬 필요는 없지만 상태관리를 해야 될 때 useRef()를 유용하게 쓸 수 있다.

Ref 사용 사례

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

비제어 컴포넌트 (Uncontrolled Component)

대부분 경우에 폼을 구현하는데 제어 컴포넌트를 사용하는 것이 좋다.
제어 컴포넌트에서 폼 데이터는 React 컴포넌트에서 다루지만,
대안인 비제어 컴포넌트는 DOM 자체에서 폼 데이터가 다루어지며 DOM에서 폼 데이터를 가져오기 위해서는 ref를 사용해야 한다.

함수 컴포넌트 ref 사용법

  1. import에 { useRef } 추가

    import { useRef } from 'react';
  2. useRef() 변수 선언

    const inputRef = useRef();
  3. 값을 받을 엘리먼트의 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>
    	);
    }

클래스 컴포넌트 ref 사용법

  1. import에 { createRef } 추가

    import { createRef } from 'react';
  2. createRef() 변수 선언

    this.myRef = React.createRef();
  3. 값을 받을 엘리먼트의 ref 속성 값에 createRef 설정
    createRef()의 객체 안에는 current라는 키가 자동으로 들어있으며 current에 값을 받을 엘리먼트가 들어가게 된다

    class MyComponent extends React.Component {
    	constructor(props) {
    		super(props);
    		this.myRef = React.createRef();
    	}
    	render() {
    		return <div ref={this.myRef} />;
    	}
    }

Forwarding Refs

부모 컴포넌트가 자식 컴포넌트의 Ref를 전달받으려면 자식 컴포넌트가 클래스 컴포넌트일 때에만 작동하며, 자식 컴포넌트가 함수 컴포넌트일 때는 React 16.3 이후 버전의 Forwarding Refs를 사용해야 한다.
Forwarding Refs는 부모 컴포넌트가 자식 컴포넌트의 ref를 자신의 ref로써 관리할 수 있다.

Forwarding Refs 사용법

  1. 부모 컴포넌트의 import에 { useRef } 추가 후 useRef() 변수 선언

    import React, { useRef } from 'react';
    export default function ParentCompnt() {
    	const catRef = useRef();
    	return (
           <ChildrenCompnt a={"a"} ref={catRef} />
    	);
    }
  2. 자식 컴포넌트의 import에 { forwardRef } 추가

    import React, { forwardRef } from "react";
  3. 인자(props, ref)를 받아 forwardRef() 로 감싼다.

    const ChildrenCompnt = forwardRef((props, ref) => {
    	return (
    		<div>
    			<img
    				src="ghibli.png"
    				alt="welcome Ghibli"
    				style={{ width: "150px" }}
    			></img>
    		</div>
    	);
    });
  4. 값을 받을 엘리먼트의 ref 속성 값에 useRef의 객체로 설정

    const ChildrenCompnt = forwardRef((props, ref) => {
    	return (
    		<div>
    			<img
    				src="ghibli.png"
    				alt="welcome Ghibli"
    				style={{ width: "150px" }}
                   /* ↓ 이부분 */
                   ref={ref}
    			></img>
    		</div>
    	);
    });

Callback refs

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} />
	);
}
profile
까먹지마도토도토잠보🐘

0개의 댓글