[React] ๐Ÿ forwardRef, ๐Ÿ callbackRef ์‚ฌ์šฉ๋ฒ•

TATAยท2023๋…„ 2์›” 22์ผ
0

React

๋ชฉ๋ก ๋ณด๊ธฐ
12/32

โ–ท forwardRef

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์„ฑํ•œ useRef๋ฅผ
์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ๋„˜๊ธธ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

์ฆ‰, ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ref๋ฅผ ๋ถ€๋ชจ์—๊ฒŒ ๊ณต๊ฐœํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

โ—๏ธ์ฐธ๊ณ ) ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ DOM ๋…ธ๋“œ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ ์ปดํฌ๋„ŒํŠธ์˜ ์บก์Šํ™”๋ฅผ ํŒŒ๊ดดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ถŒ์žฅ๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.


๐Ÿ  forwardRef ์‚ฌ์šฉ๋ฒ•

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ

์ผ๋ฐ˜ props์ฒ˜๋Ÿผ props.ref๋กœ ๋„˜๊ธฐ์ง€๋Š” ๋ชปํ•œ๋‹ค.

// useRef ๊ฐ€์ ธ์˜ค๊ธฐ
import React, { useRef } from "react";
import Child from "./Child"

function parents() {
  const parentsRef = useRef();
  
  return (
  	<>
      <h2>์—ฌ๊ธฐ๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ</h2>
      <Child ref={parentsRef}> // ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ref๋ฅผ ๋„˜๊น€
    </>
  )
}

์ž์‹ ์ปดํฌ๋„ŒํŠธ

// forwardRef ๊ฐ€์ ธ์˜ค๊ธฐ
import React, { forwardRef } from "react";

// ํ•จ์ˆ˜ ์•ž์— forwardRef๋ถ™์ด๊ธฐ
const Child = forwardRef (props, ref) => {
  
  return (
    <>
      <img src="์ฃผ์†Œ" alt="img" ref={ref} /> // img์˜ ref๋ฅผ ๊ฐ€์ ธ์˜ด
    </>
  )
}
      
export default Child;

forwardRef๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋†’์€ ํ™•๋ฅ ๋กœ useImperativeHandle์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.


๐Ÿ  useImperativeHandle

ref๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ๋ณด์—ฌ์ง€๋Š”
์ธ์Šคํ„ด์Šค ๊ฐ’์„ ์‚ฌ์šฉ์žํ™”(customizes) ํ•œ๋‹ค.

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ

// useRef ๊ฐ€์ ธ์˜ค๊ธฐ
import React, { useRef } from "react";
import Child from "./Child"

function parents() {
  const inputRef = useRef();
  
  return (
  	<>
      <h2>์—ฌ๊ธฐ๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ</h2>
      <Child ref={inputRef}> // ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ref๋ฅผ ๋„˜๊น€
      <button onClick={() => inputRef.current.inputFocus()}>
        ๋‚  ๋ˆŒ๋Ÿฌ๋„ ํฌ์ปค์Šค
      </button>
    </>
  )
}

์ž์‹ ์ปดํฌ๋„ŒํŠธ

import React, { forwardRef } from "react";

// ํ•จ์ˆ˜ ์•ž์— forwardRef๋ถ™์ด๊ธฐ
const Child = forwardRef (props, ref) => {
    const inputRef = useRef();// ์ž์‹์˜ ref๋ฅผ ๋งŒ๋“ฌ
  
  // ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” ๋ถ€๋ชจ์˜ ref
  // ๋ถ€๋ชจ๋Š” ์ด ๋กœ์ง์„ ๋ชจ๋ฅธ๋‹ค.
  // ์œ„๋กœ ๋Œ์–ด์˜ฌ๋ฆฌ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ทธ๋ƒฅ ref.current๋กœ ์ ‘๊ทผํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  useImperativeHandle(ref, () => {
    inputFocus: () => {
      inputRef.current.foucus();
    }
  })
  
  return (
    <>
      <input ref={inputRef} ... />
    </>
  )
}

๐Ÿ  useRef ๋ฆฌ๋ Œ๋” ์˜ˆ์‹œ

import React, { useRef } from "react";
import Child from "./Child"

function parents() {
  const parentsRef = useRef(); // ์ž์‹์—๊ฒŒ ๋„˜๊ฒจ์ค„ ref 
  const myRef = useRef(0); // ๋ถ€๋ชจ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ref
  
  const [state, setState] = useState(0);
  
  return (
  	<>
      <h2>์—ฌ๊ธฐ๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ</h2>
      <Child ref={parentsRef}> // ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ref๋ฅผ ๋„˜๊น€
    
      // ํด๋ฆญํ•  ๋•Œ๋งˆ๋‹ค 1 ์ฆ๊ฐ€. but, ๋ฆฌ๋ Œ๋”๋ง ์‹œ ๋™์ž‘์€ ์•ˆํ•˜๊ณ  ๊ฐ’๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์Œ.
      // 4๋ฒˆ ํด๋ฆญ ์‹œ 4๊ฐ€ ์•ˆ๋˜๊ณ  0์œผ๋กœ ๋ณด์—ฌ์ง.
      // ์•„๋ž˜ "Click me!"๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ทธ์ œ์„œ์•ผ 4๋กœ ์—…๋ฐ์ดํŠธ๋˜์–ด ๋ณด์—ฌ์ง„๋‹ค.
      <button onClick={() => (myRef.current = myRef.current + 1)}></button>

      // ํด๋ฆญํ•˜๋ฉด ์ƒํƒœ๊ฐ’ 1 ์ฆ๊ฐ€. myRef์˜ ๊ฐ’์ด ์—…๋ฐ์ดํŠธ ๋จ.
      <button onClick={() => setState(state + 1)}>Click me!</button>
      
    </>
  )
}

๐Ÿ  ์ฝœ๋ฐฑref ์‚ฌ์šฉ๋ฒ•

๋ถ€๋ชจ๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ref๋ฅผ ๋„˜๊ฒจ์„œ
์ž์‹์ด ๊ทธ ref๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ ๋ถ€๋ชจ๋Š” ์•Œ์ง€ ๋ชปํ•œ๋‹ค.

๋งŒ์•ฝ ๋ถ€๋ชจ๊ฐ€ ์ž์‹์—๊ฒŒ ๋„˜๊ธด ref๋ฅผ attachํ•˜๊ฑฐ๋‚˜ detachํ•  ๋•Œ
์–ด๋–ค ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ฝœ๋ฐฑ ref๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์ฆ‰, ์ž์‹์—๊ฒŒ ๋„˜๊ธด ref์˜ current ๊ฐ’์„
์ž์„ธํžˆ ์•Œ๊ณ  ์–ด๋–ค ๊ฐ’์„ ๊ตฌํ•˜๊ณ  ์‹ถ์„๋•Œ ์‚ฌ์šฉ
ํ•œ๋‹ค.

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ

import React, { useRef } from "react";
import Child from "./Child"

function parents() {
  // const parentsRef = useRef();
  const [height, setHeight] = useState(0);
  
  // ํ•จ์ˆ˜์ž„
  const callbackRef = (node) => {
    if (node !== null) { 
       // ์ž์‹ ref์˜ ์„ธ๋กœ ๊ธธ์ด๋กœ ์ƒํƒœ๊ฐ’ ๋ณ€๊ฒฝ
      setHeight(node.getBoundingClientReact().height)
      /* DOM ๋ฉ”์†Œ๋“œ getBoundingClientReact๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด
         ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ์›ํ•˜๋Š” ์š”์†Œ์˜ ์œ„์น˜ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. */ 
    }
  }
  
  return (
  	<>
      <h2>์—ฌ๊ธฐ๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ</h2>
      <Child ref={callbackRef}> // parentsRef๊ฐ€ ์•„๋‹Œ ํ•จ์ˆ˜๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค.
      
      // ์ž์‹์ด ๋ณ€๊ฒฝํ•œ ref์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€ ์„ธ๋กœ์˜ ๊ธธ์ด๋ฅผ ๋‚˜ํƒ€๋ƒ„.
      <h3>์‚ฌ์ง„ ์„ธ๋กœ ๊ธธ์ด: {height}</h3>
    </>
  )
}

์ž์‹ ์ปดํฌ๋„ŒํŠธ

// forwardRef ๊ฐ€์ ธ์˜ค๊ธฐ
import React, { forwardRef } from "react";

// ํ•จ์ˆ˜ ์•ž์— forwardRef๋ถ™์ด๊ธฐ
const Child = forwardRef (props, ref) => {
  // ์ƒํƒœ๊ฐ’ ๋งŒ๋“ค๊ธฐ
  const [loaded, setLoaded] = useState(false);
  
  
  
  return (
    <>
      <img src="์ฃผ์†Œ" alt="img"
        ref={loaded ? ref : null}  // ๋กœ๋“œ ๋  ๋•Œ ref
        onLoad={() => setLoaded(true)} /> // ๋กœ๋“œ ๋˜๋ฉด ์ƒํƒœ๊ฐ’ ๋ณ€๊ฒฝ
        // why? ์ด๋ฏธ์ง€๋ผ์„œ ๋กœ๋“œ ์•ˆ ๋˜์–ด์žˆ์„ ๋• ๋ถ€๋ชจ์—์„œ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ ์•ˆ ํ•˜๊ธฐ ๋•Œ๋ฌธ
    </>
  )
}
      
export default Child;



๐Ÿ‘‰ useRef ์‚ฌ์šฉ๋ฒ• ๋ณด๋Ÿฌ๊ฐ€๊ธฐ
๐Ÿ‘‰ (๊ณต์‹๋ฌธ์„œ)useRef, Ref์™€ DOM
๐Ÿ‘‰ (๊ณต์‹๋ฌธ์„œ)forwardRef
๐Ÿ‘‰ (๊ณต์‹๋ฌธ์„œ)useImperativeHandle
๐Ÿ‘‰ (๊ณต์‹๋ฌธ์„œ)callbackRef ์ฝœ๋ฐฑref

profile
๐Ÿพ

0๊ฐœ์˜ ๋Œ“๊ธ€