We want to hear from you!Take our 2021 Community Survey!
Support Ukraine ๐Ÿ‡บ๐Ÿ‡ฆ Help Provide Humanitarian Aid to Ukraine.

Forwarding Refs

ref ์ „๋‹ฌ์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด ์ž์‹ ์ค‘ ํ•˜๋‚˜์— ref๋ฅผ ์ž๋™์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋Œ€๋ถ€๋ถ„์˜ ์ปดํฌ๋„ŒํŠธ์— ํ•„์š”ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ, ํŠนํžˆ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ฐ™์€ ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋ณดํŽธ์ ์ธ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์•„๋ž˜์— ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

DOM ์— refs ์ „๋‹ฌํ•˜๊ธฐ

๊ธฐ๋ณธ button DOM ์š”์†Œ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” FancyButton ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€์ •ํ•ด ๋ด…์‹œ๋‹ค.

function FancyButton(props) {
  return (
    <button className="FancyButton">
      {props.children}
    </button>
  );
}

FancyButton๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋‚ด๋ถ€ button DOM ์š”์†Œ์— ๋Œ€ํ•œ ref๋ฅผ ์–ป์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์ด ์„œ๋กœ์˜ DOM ๊ตฌ์กฐ์— ์ง€๋‚˜์น˜๊ฒŒ ์˜์กดํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฐ ์บก์Šํ™”๋Š” FeedStory๋‚˜ Comment ๊ฐ™์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์˜ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ๋ฐ”๋žŒ์งํ•˜์ง€๋งŒ, FancyButton์ด๋‚˜ MyTextInput๊ณผ ๊ฐ™์€ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์€ โ€œ๋ง๋‹จโ€ ์š”์†Œ์—์„œ๋Š” ๋ถˆํŽธํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์ผ๋ฐ˜์ ์ธ DOM button, input๊ณผ ์œ ์‚ฌํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์— ๊ฑธ์ณ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํฌ์ปค์Šค, ์„ ํƒ, ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ด๋Ÿฐ DOM ๋…ธ๋“œ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Ref ์ „๋‹ฌํ•˜๊ธฐ๋Š” ์ผ๋ถ€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ˆ˜์‹ ํ•œ ref๋ฅผ ๋ฐ›์•„ ์กฐ๊ธˆ ๋” ์•„๋ž˜๋กœ ์ „๋‹ฌ(์ฆ‰, โ€œ์ „์†กโ€)ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ตํŠธ์ธ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

์•„๋ž˜์˜ ์˜ˆ์—์„œ FancyButton์€ React.forwardRef๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ „๋‹ฌ๋œ ref๋ฅผ ์–ป๊ณ , ๊ทธ๊ฒƒ์„ ๋ Œ๋”๋ง ๋˜๋Š” DOM button์œผ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

const FancyButton = React.forwardRef((props, ref) => (  <button ref={ref} className="FancyButton">    {props.children}
  </button>
));

// ์ด์ œ DOM ๋ฒ„ํŠผ์œผ๋กœ ref๋ฅผ ์ž‘์ ‘ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

์ด๋Ÿฐ ๋ฐฉ๋ฒ•์œผ๋กœ FancyButton์„ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์€ button DOM ๋…ธ๋“œ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ณ , ํ•„์š”ํ•œ ๊ฒฝ์šฐ DOM button์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์‹œ์—์„œ ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚˜๋Š”์ง€ ๋‹จ๊ณ„๋ณ„๋กœ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

  1. React.createRef๋ฅผ ํ˜ธ์ถœํ•ด์„œ React ref๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ref ๋ณ€์ˆ˜์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.
  2. ref๋ฅผ JSX ์†์„ฑ์œผ๋กœ ์ง€์ •ํ•ด์„œ <FancyButton ref={ref}>๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  3. React๋Š” ์ด ref๋ฅผ forwardRef ๋‚ด๋ถ€์˜ (props, ref) => ... ํ•จ์ˆ˜์˜ ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  4. ์ด ref๋ฅผ JSX ์†์„ฑ์œผ๋กœ ์ง€์ •ํ•ด์„œ <button ref={ref}>์œผ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  5. ref๊ฐ€ ์ฒจ๋ถ€๋˜๋ฉด ref.current๋Š” <button> DOM ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์•Œ์•„๋‘๊ธฐ

๋‘ ๋ฒˆ์งธ ref ์ธ์ž๋Š” React.forwardRef์™€ ๊ฐ™์ด ํ˜ธ์ถœ๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ–ˆ์„ ๋•Œ์—๋งŒ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜ ํ•จ์ˆ˜๋‚˜ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋Š” ref ์ธ์ž๋ฅผ ๋ฐ›์ง€๋„ ์•Š๊ณ  props์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค.

Ref ์ „๋‹ฌ์€ DOM ์ปดํฌ๋„ŒํŠธ์—๋งŒ ํ•œ์ •์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์—๋„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์œ ์ง€๊ด€๋ฆฌ์ž๋ฅผ ์œ„ํ•œ ์ฃผ์˜์‚ฌํ•ญ

์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ forwardRef๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ•  ๋•Œ ์ด๊ฒƒ์„ ๋ณ€๊ฒฝ์‚ฌํ•ญ์œผ๋กœ ๊ฐ„์ฃผํ•˜๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ƒˆ๋กœ์šด ์ค‘์š” ๋ฒ„์ „์„ ๋ฆด๋ฆฌ์ฆˆ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ฃผ๋ชฉํ•  ๋งŒํ•˜๊ฒŒ (ref๊ฐ€ ํ• ๋‹น๋˜๋Š” ๊ฒƒ์ด ๋ฌด์—‡์ด๋ฉฐ ๋‚ด๋ณด๋‚ด๋Š” ์œ ํ˜•์€ ๋ฌด์—‡์ธ๊ฐ€์™€ ๊ฐ™์€) ๋‹ค๋ฅธ ๋™์ž‘์„ ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๊ณ  ์ด์ „ ๋™์ž‘์— ์˜์กดํ•˜๋Š” ์•ฑ์ด๋‚˜ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์†์ƒ๋  ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์กฐ๊ฑด์ ์œผ๋กœ React.forwardRef๊ฐ€ ์กด์žฌํ•  ๋•Œ ์กฐ๊ฑด๋ถ€๋กœ ์ ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ™์€ ์ด์œ ๋กœ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค: ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์„ ๋ณ€๊ฒฝํ•˜๊ณ  React ๊ทธ ์ž์ฒด๋ฅผ ์—…๋ฐ์ดํŠธํ•  ๋•Œ ์‚ฌ์šฉ์ž ์•ฑ์„ ์†์ƒ์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ ์ฐจ์› ์ปดํฌ๋„ŒํŠธ์—์„œ์˜ ref ์ „๋‹ฌํ•˜๊ธฐ

์ด ๊ธฐ์ˆ ์€ (HOC๋กœ ์•Œ๋ ค์ง„) ๊ณ ์ฐจ์› ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ถ€๋ถ„์ ์œผ๋กœ ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ˜์†”์— ์ปดํฌ๋„ŒํŠธ props๋ฅผ ๋กœ๊น… ํ•˜๋Š” HOC ์˜ˆ์‹œ๋กœ ์„ค๋ช…์„ ์‹œ์ž‘ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

function logProps(WrappedComponent) {  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      return <WrappedComponent {...this.props} />;    }
  }

  return LogProps;
}

โ€œlogPropsโ€ HOC๋Š” ๋ชจ๋“  props๋ฅผ ๋ž˜ํ•‘ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•˜๋ฏ€๋กœ ๋ Œ๋”๋ง ๋œ ๊ฒฐ๊ณผ๊ฐ€ ๋™์ผํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ด HOC๋ฅผ ์‚ฌ์šฉํ•ด์„œ โ€œfancy buttonโ€ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•˜๋Š” ๋ชจ๋“  props๋ฅผ ๊ธฐ๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class FancyButton extends React.Component {
  focus() {
    // ...
  }

  // ...
}

// FancyButton์„ ๋‚ด๋ณด๋‚ด๋Š” ๋Œ€์‹  LogProps๋ฅผ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค.
// ๊ทธ๋ž˜๋„ FancyButton์„ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.
export default logProps(FancyButton);

์œ„ ์˜ˆ์‹œ์—์„œ ํ•œ ๊ฐ€์ง€ ์ฃผ์˜์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค: refs๋Š” ์ „๋‹ฌ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ref๋Š” prop์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. key์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ref๋Š” React์—์„œ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. HOC์— ref๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ref๋Š” ๋ž˜ํ•‘ ๋œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฐ€์žฅ ๋ฐ”๊นฅ์ชฝ ์ปจํ…Œ์ด๋„ˆ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

FancyButton ์ปดํฌ๋„ŒํŠธ๋ฅผ ์œ„ํ•œ refs๊ฐ€ ์‹ค์ œ๋กœ๋Š” LogProps ์ปดํฌ๋„ŒํŠธ์— ์ฒจ๋ถ€๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

import FancyButton from './FancyButton';

const ref = React.createRef();
// ๊ฐ€์ ธ์˜จ FancyButton ์ปดํฌ๋„ŒํŠธ๋Š” LogProps HOC์ž…๋‹ˆ๋‹ค.
// ๋ Œ๋”๋ง๋œ ๊ฒฐ๊ณผ๊ฐ€ ๋™์ผํ•˜๋‹ค๊ณ  ํ•˜๋”๋ผ๋„,
// ref๋Š” ๋‚ด๋ถ€ FancyButton ์ปดํฌ๋„ŒํŠธ ๋Œ€์‹  LogProps๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค!
// ์ด๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ์˜ˆ๋ฅผ ๋“ค์–ด ref.current.focus()๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

<FancyButton
  label="Click Me"
  handleClick={handleClick}
  ref={ref}/>;

๋‹คํ–‰ํžˆ๋„ React.forwardRef API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‚ด๋ถ€ FancyButton ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ refs๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. React.forwardRef๋Š” props์™€ ref ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์•„ React ๋…ธ๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ Œ๋”๋ง ํ•จ์ˆ˜๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

function logProps(Component) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      const {forwardedRef, ...rest} = this.props;
      // ์‚ฌ์šฉ์ž ์ •์˜ prop "forwardedRef"๋ฅผ ref๋กœ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.
      return <Component ref={forwardedRef} {...rest} />;    }
  }

  // React.forwardRef์—์„œ ์ œ๊ณตํ•˜๋Š” ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ "ref"์— ์ฃผ์˜ํ•ด์ฃผ์„ธ์š”.
  // ๊ฐ€๋ น "forwardedRef"๊ฐ™์€ ์ผ๋ฐ˜ prop์œผ๋กœ LogProps์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  // ๊ทธ ๋‹ค์Œ Component์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  return React.forwardRef((props, ref) => {    return <LogProps {...props} forwardedRef={ref} />;  });}

DevTools์— ์‚ฌ์šฉ์ž ์ •์˜ ์ด๋ฆ„ ํ‘œ์‹œํ•˜๊ธฐ

React.forwardRef๋Š” ๋ Œ๋”๋ง ํ•จ์ˆ˜๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. React DevTools๋Š” ์ด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ref ์ „๋‹ฌ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•ด์„œ ๋ฌด์—‡์„ ํ‘œ์‹œํ•  ๊ฒƒ์ธ์ง€ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋กœ, ๋‹ค์Œ์˜ ์ปดํฌ๋„ŒํŠธ๋Š” DevTools์— โ€ForwardRefโ€œ๋กœ ๋‚˜ํƒ€๋‚  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

const WrappedComponent = React.forwardRef((props, ref) => {
  return <LogProps {...props} forwardedRef={ref} />;
});

๋ Œ๋”๋ง ํ•จ์ˆ˜๋ฅผ ์ง€์ •ํ•˜๋ฉด DevTools์— ํ•ด๋‹น ์ด๋ฆ„๋„ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. (์˜ˆ, โ€ForwardRef(myFunction)โ€œ)

const WrappedComponent = React.forwardRef(
  function myFunction(props, ref) {
    return <LogProps {...props} forwardedRef={ref} />;
  }
);

๊ฐ์‹ธ๊ณ  ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ํฌํ•จํ•˜๋„๋ก ํ•จ์ˆ˜์˜ displayName ์†์„ฑ์„ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

function logProps(Component) {
  class LogProps extends React.Component {
    // ...
  }

  function forwardRef(props, ref) {
    return <LogProps {...props} forwardedRef={ref} />;
  }

  // DevTools์—์„œ ์ด ์ปดํฌ๋„ŒํŠธ์— ์กฐ๊ธˆ ๋” ์œ ์šฉํ•œ ํ‘œ์‹œ ์ด๋ฆ„์„ ์ง€์ •ํ•˜์„ธ์š”.
  // ์˜ˆ, "ForwardRef(logProps(MyComponent))"
  const name = Component.displayName || Component.name;  forwardRef.displayName = `logProps(${name})`;
  return React.forwardRef(forwardRef);
}

Is this page useful?Edit this page