๐Ÿ“ ์˜ค๋Š˜ ํ•œ ๊ฒƒ

  1. react - ๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ(ref ์ƒ์„ฑ ๋ฐ ์ ‘๊ทผ) vs ์ œ์–ด ์ปดํฌ๋„ŒํŠธ

๐Ÿ“š ๋ฐฐ์šด ๊ฒƒ

์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๋‚ด์šฉ์ด๊ฑฐ๋‚˜ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์› ๋˜ ๋ถ€๋ถ„๋งŒ ์ •๋ฆฌ

1. ๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ

React: ์ œ์–ด ์ปดํฌ๋„ŒํŠธ์™€ ๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ์˜ ์ฐจ์ด์  ์ฐธ๊ณ 

์ œ์–ด ์ปดํฌ๋„ŒํŠธ์—์„œ ํผ ๋ฐ์ดํ„ฐ๋Š” React ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‹ค๋ฃจ์–ด์ง€๊ณ , ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€ ๋กœ์ง์— ์˜ํ•ด์„œ ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๋Š” ๊ฐ’์ด ๋ณ€ํ•œ๋‹ค.

๋ฐ˜๋ฉด์—, ๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ํผ ๋ฐ์ดํ„ฐ๋Š” DOM ์ž์ฒด์—์„œ ๋‹ค๋ฃจ์–ด์ง€๊ณ , ์‚ฌ์šฉ์ž์— ์˜ํ•ด ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๋Š” ๊ฐ’์ด ๋ณ€ํ•œ๋‹ค.

1) Ref์™€ DOM

(1) ref๋ž€?

ref๋Š” render ๋ฉ”์„œ๋“œ์—์„œ ์ƒ์„ฑ๋œ 'DOM ๋…ธ๋“œ'๋‚˜ 'React ์—˜๋ฆฌ๋จผํŠธ'์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.
์ผ๋ฐ˜์ ์œผ๋กœ React์˜ ๋ฐ์ดํ„ฐ ํ”Œ๋กœ์šฐ์—์„œ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๋ฉด ์ƒˆ๋กœ์šด props๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•ด์•ผ ํ•œ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜, ref๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

ref๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํ•ด๊ฒฐ๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด ref๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ง€์–‘๋œ๋‹ค.
ref๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.

  • ํฌ์ปค์Šค, ํ…์ŠคํŠธ ์„ ํƒ์˜์—ญ, ํ˜น์€ ๋ฏธ๋””์–ด์˜ ์žฌ์ƒ์„ ๊ด€๋ฆฌํ•  ๋•Œ
  • ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ง์ ‘์ ์œผ๋กœ ์‹คํ–‰์‹œํ‚ฌ ๋•Œ
  • ์„œ๋“œ ํŒŒํ‹ฐ DOM ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ React์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ๋•Œ

(2) ref ์ƒ์„ฑ ๋ฐ ์ ‘๊ทผ

  • DOM ์—˜๋ฆฌ๋จผํŠธ์— Ref ์‚ฌ์šฉํ•˜๊ธฐ

    button input์„ ํด๋ฆญํ•˜๋ฉด text input์ด focus ๋˜๋„๋ก ํ•˜๋ ค๊ณ  ํ•œ๋‹ค.
    render ๋ฉ”์„œ๋“œ์—์„œ ์ƒ์„ฑ๋œ DOM ์—˜๋ฆฌ๋จผํŠธ์— ์ ‘๊ทผํ•˜๋ ค๋Š” ๊ฒƒ์ด๋‹ค.

    ๋‹ค์Œ๊ณผ ๊ฐ™์ด ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ HTML ์—˜๋ฆฌ๋จผํŠธ์— ์“ฐ์ธ ๊ฒฝ์šฐ, ์ƒ์„ฑ์ž์—์„œ React.createRef()๋กœ ์ƒ์„ฑ๋œ ref๋Š”, ์ž์‹ ์„ ์ „๋‹ฌ๋ฐ›์€ DOM ์—˜๋ฆฌ๋จผํŠธ(๋‹ค์Œ ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ, input type="text")๋ฅผ current ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์œผ๋กœ ๋ฐ›๋Š”๋‹ค.

class CumstomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef(); // ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ref๋ฅผ ๊ทธ ํ”„๋กœํผํ‹ฐ๋กœ ์ถ”๊ฐ€
    this.focusTextInput = this.focusTextInput.bind(this);
  }
  
  focusTextInput() {
    this.textInput.current.focus();
    
    // console.log(this.textInput.current); // input
  }
  
  render() {
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} // ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์˜ ์–ด๋А ๊ณณ์—์„œ๋„ ref์— ์ ‘๊ทผ ๊ฐ€๋Šฅ
        />
        <input
          type="button"
          value="focus"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}
  • ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์— ref ์‚ฌ์šฉํ•˜๊ธฐ

    ํ•œํŽธ, ์—ฌ๊ธฐ์„œ ๋” ๋‚˜์•„๊ฐ€ button input์„ ์ง์ ‘ ํด๋ฆญํ•˜๊ธฐ๋„ ์ „์— ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋œ ์งํ›„ text input์ด ์ฆ‰์‹œ ํฌ์ปค์Šค ๋ฐ›๋„๋ก ํ•˜๋ ค๊ณ  ํ•œ๋‹ค.
    render ๋ฉ”์„œ๋“œ์—์„œ React ์ปดํฌ๋„ŒํŠธ์˜ ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•˜๋ ค๋Š” ๊ฒƒ์ด๋‹ค.

    ๋‹ค์Œ๊ณผ ๊ฐ™์ด ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ ์ปค์Šคํ…€ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์— ์“ฐ์ธ ๊ฒฝ์šฐ, ์ƒ์„ฑ์ž์—์„œ React.createRef()๋กœ ์ƒ์„ฑ๋œ ref๋Š”, ๋งˆ์šดํŠธ๋œ ์ปดํฌ๋„ŒํŠธ์˜ ์ธ์Šคํ„ด์Šค(๋‹ค์Œ ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ, CustomTextInput)๋ฅผ current ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์œผ๋กœ ๋ฐ›๋Š”๋‹ค.

class AutoFocusTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  
  componentDidMount() {
    this.textInput.current.focusTextInput();
    
    // console.log(this.textInput.current); // CustomTextInput
  }
  
  render() {
    return (
      <CustomTextInput ref={this.textInput} />
    );
  }
}

ReactDOM.render(
  <AutoFocusTextInput />,
  document.getElementById("root")
);
  • ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—/์—์„œ ref ์‚ฌ์šฉํ•˜๊ธฐ

    (1) ๋ฐ˜๋ฉด์—, ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ'์—๋Š”' ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

    (2) ๊ทธ๋Ÿฌ๋‚˜, ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ'์—์„œ' (render ๋ฉ”์„œ๋“œ์—์„œ ์ƒ์„ฑ๋œ DOM ์—˜๋ฆฌ๋จผํŠธ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด) ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•˜๋‹ค.

    cf. ์ด๋•Œ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” createRef ๋Œ€์‹  useRef๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.
    ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ createRef๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด setState๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค createRef๋„ ๋‹ค์‹œ ํ˜ธ์ถœ๋˜์–ด ref.current๊ฐ€ null๋กœ ์ดˆ๊ธฐํ™”๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
    ๋”ฐ๋ผ์„œ, ref.current์˜ ๊ฐ’์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด useRef๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

// (1)์˜ ๊ฒฝ์šฐ
function MyFunctionComponent() {
  return <input />;
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  render() {
    // ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ'์—๋Š”' ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅ
    return (
      <MyFunctionComponent ref={this.textInput} />
    );
  }
}
// (2)์˜ ๊ฒฝ์šฐ
function CustomTextInput(props) {
  // textInput์€ ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋˜๊ธฐ ์œ„ํ•ด์„œ ์ด๊ณณ์—์„œ ์ •์˜๋˜์–ด์•ผ ํ•จ
  const textInput = useRef(null);

  function handleClick() {
    textInput.current.focus();
  }

  return (
    <div>
      <input
        type="text"
        ref={textInput} /> {/* ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ'์—์„œ' ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ์‚ฌ์šฉ ๊ฐ€๋Šฅ */}
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );
}

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ, '์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ DOM ์—˜๋ฆฌ๋จผํŠธ'์— ์ ‘๊ทผํ•˜๊ณ ์ž ํ•  ๋•Œ ref๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
(์œ„ ์˜ˆ์ œ๋“ค์€ '์ง์ ‘ ๋ Œ๋”๋งํ•˜๋Š” DOM ์—˜๋ฆฌ๋จผํŠธ' ํ˜น์€ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ '์ž์‹ ์ปดํฌ๋„ŒํŠธ'์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ref๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ์˜€๋‹ค.)

'์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ DOM ์—˜๋ฆฌ๋จผํŠธ'์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋„ ์œ„์™€ ๊ฐ™์ด ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธด ํ•˜์ง€๋งŒ
์ด๋Š” ์œ„์—์„œ ์‚ดํŽด๋ดค๋“ฏ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ์ธ์Šคํ„ด์Šค์˜ DOM ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค๋Š” ์ ์—์„œ, ๊ทธ๋ฆฌ๊ณ  ์ž์‹ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์ธ ๊ฒฝ์šฐ์—๋Š” ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š”๋‹ค๋Š” ์ ์—์„œ, ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋‹ค.

๋Œ€์‹ ์— (React 16.3 ์ดํ›„ ๋ฒ„์ „์˜ React๋ฅผ ์‚ฌ์šฉ ์ค‘์ด๋ผ๋ฉด) ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ '์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ DOM ์—˜๋ฆฌ๋จผํŠธ'์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ref๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ref๋ฅผ ์ž์‹ ์˜ ref๋กœ์„œ ์™ธ๋ถ€์— ๋…ธ์ถœ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์„ ๋งํ•œ๋‹ค.

React.forwardRef()๋ฅผ ์ด์šฉํ•ด ์ผ๋ถ€ ์ปดํฌ๋„ŒํŠธ(๋‹ค์Œ ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ, < FancyButton />)๊ฐ€ ์ˆ˜์‹ ํ•œ ref๋ฅผ ๋ฐ›์•„ ์กฐ๊ธˆ ๋” ์•„๋ž˜๋กœ ์ „๋‹ฌ(์ฆ‰, '์ „์†ก')ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ตํŠธ์ธ ๊ธฐ๋Šฅ์ด๋‹ค. (์˜ตํŠธ์ธ: ๋‹น์‚ฌ์ž๊ฐ€ ๊ฐœ์ธ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘์„ ํ—ˆ์šฉํ•˜๊ธฐ ์ „๊นŒ์ง€ ๋‹น์‚ฌ์ž์˜ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘์„ ๊ธˆ์ง€ํ•˜๋Š” ์ œ๋„)
ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ HTML ์—˜๋ฆฌ๋จผํŠธ์— ์“ฐ์ธ ๊ฒฝ์šฐ, ref ๊ฐ์ฒด๋Š” ์ž์‹ ์„ ์ „๋‹ฌ๋ฐ›์€ DOM ์—˜๋ฆฌ๋จผํŠธ๋ฅผ, ๊ทธ current ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์œผ๋กœ ๋ฐ›๋Š” ๊ฒƒ์„ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.

// 3. ์ด ref๋ฅผ forwardRef ๋‚ด๋ถ€์˜ (props, ref) => ... ํ•จ์ˆ˜์˜ ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ „๋‹ฌ
const FancyButton = React.forwardRef((props, ref) => {
  return (
    <button ref={ref} className="FancyButton"> {/* 4. ์ด ref๋ฅผ <button>์œผ๋กœ ์ „๋‹ฌ */}
      {props.children}
    </button>
  );
});

const App = () => {
  const ref = React.createRef(); // 1. createRef๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ref๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ref ๋ณ€์ˆ˜์— ํ• ๋‹น
  
  const onMouseOver = () => {
    ref.current.focus();
    
    // 5. ์ตœ์ดˆ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง์ด ๋๋‚˜๋ฉด, ref.current๋Š” <button> DOM ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋จ
    // console.log(ref.current); // <button class="FancyButton">Click me!</button>
  };
  
  return (
    <div>
      <input onMouseOver={onMouseOver}/>
      <FancyButton ref={ref}>Click me!</FancyButton> {/* 2. ref๋ฅผ <FancyButton />์œผ๋กœ ์ „๋‹ฌ */}
    </div>
  );
};

ReactDOM.render(
  <App/>,
  document.getElementById("root")
);

(3) ์ฝœ๋ฐฑ ref

ref๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ref๊ฐ€ ์„ค์ •๋˜๊ณ  ํ•ด์ œ๋˜๋Š” ์ƒํ™ฉ์„ ์„ธ์„ธํ•˜๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ์ฝœ๋ฐฑ ref๊ฐ€ ์žˆ๋‹ค.

์œ„์—์„œ ์‚ดํŽด๋ดค๋˜ ๊ฒƒ๊ณผ๋Š” ๋‹ฌ๋ฆฌ ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ์— React.createRef()๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ref ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋Œ€์‹ ์—, ref ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

ref ์ฝœ๋ฐฑ์€ ์ธ๋ผ์ธ ํ•จ์ˆ˜๋กœ ์„ ์–ธํ•˜๊ธฐ๋ณด๋‹ค ํด๋ž˜์Šค์— ๋ฐ”์ธ๋”ฉ๋œ ๋ฉ”์„œ๋“œ๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

ํ•œํŽธ, ref๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์ž‘์—…๊ณผ ref ์ฝœ๋ฐฑ ๋ชจ๋‘ componentDidMount ๋˜๋Š” componentDidUpdate๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— ์ˆ˜ํ–‰๋˜๊ณ  ํ˜ธ์ถœ๋œ๋‹ค.

  • DOM ์—˜๋ฆฌ๋จผํŠธ์— ์ฝœ๋ฐฑ ref ์ „๋‹ฌํ•˜๊ธฐ
class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);

    this.textInput = null; // 1. DOM ์—˜๋ฆฌ๋จผํŠธ(๋˜๋Š” ์ž์‹ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค)์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์ €์žฅํ• , ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์˜ ํ”„๋กœํผํ‹ฐ ๋งŒ๋“ค๊ธฐ

    this.setTextInputRef = element => {
      this.textInput = element; // 4. ์ด๋ฅผ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ์— ์ €์žฅํ•จ
      
      // 3.  ref ์ฝœ๋ฐฑ์€ ref ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ ์“ฐ์ธ DOM ์—˜๋ฆฌ๋จผํŠธ(๋˜๋Š” ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ์ธ์Šคํ„ด์Šค)๋ฅผ ์ธ์ž๋กœ ๋ฐ›์Œ
      // console.log(element); // <input type="text">
    };

    // ( constructor ์•ˆ์— ์ •์˜๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ๋ฐ‘์—์„œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉ๋  ๋•Œ this ๋ฐ”์ธ๋”ฉ ์•ˆํ•ด๋„ ๋œ๋‹ค )
    this.focusTextInput = () => {
      // 6. ์ตœ์ดˆ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ์‹œ ์ž๋™์œผ๋กœ ํฌ์ปค์Šค ๋จ, ๊ทธ ํ›„ ๋ฒ„ํŠผ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค ํฌ์ปค์Šค๋จ
      // => render ๋ฉ”์„œ๋“œ์— ์˜ํ•ด ์ƒ์„ฑ๋˜๋Š” DOM ์—˜๋ฆฌ๋จผํŠธ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค!
      if (this.textInput) {
        this.textInput.focus();
      }
    };
  } // ( ...์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ constructor )

  componentDidMount() { // 5. ์ตœ์ดˆ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง์ด ๋๋‚œ ํ›„ componentDidMount ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋จ
    this.focusTextInput();
  }

  render() {
    return (
      <div>
        <input
          type="text"
          ref={this.setTextInputRef} {/* 2. render ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด componentDidMount ํ˜ธ์ถœ ์ „์— ref ์ฝœ๋ฐฑ์ด ํ˜ธ์ถœ๋จ */}
        />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

ReactDOM.render(
  <CustomTextInput/>,
  document.getElementById("root")
);
  • ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์ฝœ๋ฐฑ ref ์ „๋‹ฌํ•˜๊ธฐ
function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} /> {/* ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ'์—์„ ' ref๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. */}
    </div>
  );
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    
    this.inputElement = null;
  }
  
  inputRef(element) {
    this.inputElement = element;
  }
  
  componentDidMount() {
    this.inputElement.focus();
  }
  
  render() {
    return (
      <CustomTextInput inputRef={el => this.inputElement = el} />
      {/* props ํ”„๋กœํผํ‹ฐ๋กœ inputRef(ref ์ฝœ๋ฐฑ)๋ฅผ ์ „๋‹ฌํ–ˆ๋‹ค.
      โ€ป ์ฃผ์˜! ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ'์—๋Š”' ref๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
      ์—ฌ๊ธฐ์„œ๋Š” ref๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒŒ ์•„๋‹ˆ๋ผ inputRef๋ผ๋Š” prop์„ ์ž‘์„ฑํ•œ ๊ฒƒ์ด๋‹ค.  */}
    );
  }
}

ReactDOM.render(
  <Parent />,
  document.getElementById("root")
);

2) defaultValue

React ๋ Œ๋”๋ง ์ƒ๋ช… ์ฃผ๊ธฐ์—์„œ ํผ ์—˜๋ฆฌ๋จผํŠธ์˜ value ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋Š” DOM์˜ value๋ฅผ ๋Œ€์ฒดํ•œ๋‹ค.
๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ดˆ๊นƒ๊ฐ’์„ ์ง€์ •ํ•ด์ค„ ์ˆœ ์žˆ์ง€๋งŒ, ๊ทธ ์ดํ›„์˜ ์—…๋ฐ์ดํŠธ๋Š” ์ œ์–ดํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
์ด๋ฅผ ์œ„ํ•ด JSX์—์„œ์˜ value ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๋Œ€์‹  defaultValue ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ ๋œ ํ›„์— defaultValue ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ DOM์˜ ๊ฐ’์€ ์—…๋ฐ์ดํŠธ ๋˜์ง€ ์•Š๋Š”๋‹ค.

< input type="checkbox" >์™€ < input type="radio" >๋Š” defaultChecked๋ฅผ ์ง€์›ํ•˜๊ณ , < input >๊ณผ < select >, < textarea >๋Š” defaultValue๋ฅผ ์ง€์›ํ•œ๋‹ค.

class CustomForm extends React.Component {
  constructor(props) {
    super(props);
    
    this.input = React.createRef();
 
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  
  handleSubmit(event) {
    event.preventDefault();
    console.log(this.input.current.value);
  }
  
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input
            defaultValue="Bob"
            type="text"
            ref={this.input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

ReactDOM.render(
  <CustomForm />,
  document.getElementById("root")
);

3) ํŒŒ์ผ ์ž…๋ ฅ ํƒœ๊ทธ

React์—์„œ <input type="file" />์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ ์œผ๋กœ ๊ฐ’์„ ์„ค์ • ํ•  ์ˆ˜ ์—†๊ณ  ์‚ฌ์šฉ์ž๋งŒ์ด ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์ƒ ๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ์—์„œ๋Š” onSubmit ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜์—์„œ ํŒŒ์ผ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ DOM ์—˜๋ฆฌ๋จผํŠธ์— ref๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.

const CustomForm = () => {
  const fileInput = React.useRef(null);
  
  const onSubmit = (event) => {
    event.preventDefault();
    console.log(fileInput.current.files[0].name);
  };
  
  return (
    <div>
      <form onSubmit={onSubmit}>
        <label htmlFor="file">
          ํŒŒ์ผ: 
          <input id="file" type="file" ref={fileInput} />
        </label>
        <input type="submit" value="submit" />
      </form>
    </div>
  );
};

ReactDOM.render(
  <CustomForm />,
  document.getElementById("root")
);

โœจ ๋‚ด์ผ ํ•  ๊ฒƒ

  1. react effects
profile
dev log

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

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด

Powered by GraphCDN, the GraphQL CDN