μλ‘κ² μκ² λ λ΄μ©μ΄κ±°λ μ΄ν΄νκΈ° μ΄λ €μ λ λΆλΆλ§ μ 리
React: μ μ΄ μ»΄ν¬λνΈμ λΉμ μ΄ μ»΄ν¬λνΈμ μ°¨μ΄μ  μ°Έκ³
μ μ΄ μ»΄ν¬λνΈμμ νΌ λ°μ΄ν°λ React μ»΄ν¬λνΈμμ λ€λ£¨μ΄μ§κ³ , μ»΄ν¬λνΈ λ΄λΆ λ‘μ§μ μν΄μ νλ©΄μ 보μ¬μ§λ κ°μ΄ λ³νλ€.
λ°λ©΄μ, λΉμ μ΄ μ»΄ν¬λνΈμμλ νΌ λ°μ΄ν°λ DOM μ체μμ λ€λ£¨μ΄μ§κ³ , μ¬μ©μμ μν΄ νλ©΄μ 보μ¬μ§λ κ°μ΄ λ³νλ€.
refλ render λ©μλμμ μμ±λ 'DOM λ
Έλ'λ 'React μ리먼νΈ'μ μ κ·ΌνκΈ° μν΄ μ¬μ©λλ€.
μΌλ°μ μΌλ‘ Reactμ λ°μ΄ν° νλ‘μ°μμ λΆλͺ¨ μ»΄ν¬λνΈμμ μμ μ»΄ν¬λνΈλ₯Ό μμ νλ €λ©΄ μλ‘μ΄ propsλ₯Ό μ λ¬νμ¬ μμ μ»΄ν¬λνΈλ₯Ό λ€μ λ λλ§ν΄μΌ νλ€.
κ·Έλ¬λ, refλ₯Ό μ¬μ©νλ©΄ λΆλͺ¨ μ»΄ν¬λνΈμμ μμ μ»΄ν¬λνΈλ₯Ό μ§μ  μμ ν  μ μλ€.
refλ₯Ό μ¬μ©νμ§ μκ³  ν΄κ²°λ  μ μλ€λ©΄ refλ₯Ό μ¬μ©νλ κ²μ μ§μλλ€.
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")
);
refλ₯Ό μ€μ νκΈ° μν λ λ€λ₯Έ λ°©λ²μΌλ‘ refκ° μ€μ λκ³ ν΄μ λλ μν©μ μΈμΈνκ² λ€λ£° μ μλ μ½λ°± refκ° μλ€.
μμμ μ΄ν΄λ΄€λ κ²κ³Όλ λ¬λ¦¬ ref μ΄νΈλ¦¬λ·°νΈμ React.createRef()λ₯Ό ν΅ν΄ μμ±λ ref κ°μ²΄λ₯Ό μ λ¬νλ λμ μ, ref μ½λ°± ν¨μλ₯Ό μ λ¬νλ€.
ref μ½λ°±μ μΈλΌμΈ ν¨μλ‘ μ μΈνκΈ°λ³΄λ€ ν΄λμ€μ λ°μΈλ©λ λ©μλλ‘ μ μΈνλ κ²μ΄ μ’λ€.
ννΈ, refλ₯Ό μμ νλ μμ
κ³Ό ref μ½λ°± λͺ¨λ componentDidMount λλ componentDidUpdateκ° νΈμΆλκΈ° μ μ μνλκ³  νΈμΆλλ€.
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")
);
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")
);
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")
);
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")
);