[React] Ref

summereuna๐Ÿฅยท2023๋…„ 4์›” 18์ผ
0

React JS

๋ชฉ๋ก ๋ณด๊ธฐ
43/69

๐ŸŒ€ state ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑ๋œ ํ˜„์žฌ ์ฝ”๋“œ


const usernameChangeHandler = (event) => {
  setEnteredUsername(event.target.value);
};

const ageChangeHandler = (event) => {
  setEnteredAge(event.target.value);
};
  • ์‹ค์ œ๋กœ๋Š” form์„ ์ œ์ถœํ•  ๋•Œ๋งŒ setEnteredUsername()๋กœ state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ํ˜„์žฌ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ํ‚ค๊ฐ’์„ ์ž…๋ ฅ ๋ฐ›์„ ๋•Œ ๋งˆ๋‹ค ๊ณ„์† state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์žˆ๋‹ค.
  • state๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปจํŠธ๋กค ์ปดํฌ๋„ŒํŠธ๋กœ ๋งŒ๋“  ๊ฒƒ์€ ์ข‹์ง€๋งŒ ํ‚ค๋ฅผ ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด๋‚˜ ๐ŸŒ€๋น„ํšจ์œจ์ ์ด๋‹ค.
  • ์ด๋Ÿด ๋•Œ โœ…useRef() ํ›…์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

โœ… useRef()


1. useRef() ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ref ์ƒ์„ฑํ•˜๊ธฐ

  • useRef()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด DOM ์š”์†Œ์— ์ ‘๊ทผํ•˜์—ฌ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. HTML ์š”์†Œ์— ์—ฐ๊ฒฐํ•˜์—ฌ ํ•ด๋‹น ์š”์†Œ์™€ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์ดˆ๊ธฐ๊ฐ’์„ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด undefined์ด๋‹ค.
  • ๐Ÿ“ ์ฐธ๊ณ 
    ๋ชจ๋“  ๋ฆฌ์•กํŠธ ํ›…๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ useRef๋„ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ๋งŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

input๊ณผ ์—ฐ๊ฒฐํ•  ref ์ƒ์„ฑํ•˜๊ธฐ

//์‚ฌ์šฉ์ž ์ด๋ฆ„ ์ž…๋ ฅํ•˜๋Š” ์ธํ’‹๊ณผ ์—ฐ๊ฒฐํ•  ref ์ƒ์„ฑ
const nameInputRef = useRef();

//์‚ฌ์šฉ์ž ๋‚˜์ด ์ž…๋ ฅํ•˜๋Š” ์ธํ’‹๊ณผ ์—ฐ๊ฒฐํ•  ref ์ƒ์„ฑ
const ageInputRef = useRef();

useRef()๋กœ ์ƒ์„ฑ๋˜๋Š” ref ๊ฐ’์€ ํ•ญ์ƒ current prop์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด์ด๋‹ค.

  • current ํ”„๋กญ์€ ๊ทธ ref๊ฐ€ ์—ฐ๊ฒฐ๋œ ์‹ค์ œ DOM ๋…ธ๋“œ๋ฅผ ๊ฐ’์œผ๋กœ ๊ฐ€์ง„๋‹ค.
    ๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ DOM์„ ๋ฆฌ์•กํŠธ์— ์˜ํ•ด์„œ ์กฐ์ž‘ํ•˜๋ ค๊ณ  ๋ฆฌ์•กํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์ง์ ‘ DOM์„ ์กฐ์ž‘ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์ง€ ์•Š๋‹ค.
  • ์—ฌ๊ธฐ์„œ์˜ ์šฉ๋„๋Š” ํ•ด๋‹นํ•˜๋Š” input์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ์ฝ๊ธฐ ์œ„ํ•œ ์šฉ๋„์ด์ง€ ๋ญ”๊ฐ€ ์กฐ์ž‘ํ•ด์„œ ๋ฐ”๊พธ๋ ค๊ณ  ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค.

2. ์—ฐ๊ฒฐํ•  input์— ref prop์„ ์ถ”๊ฐ€ํ•˜์—ฌ ref ๊ฐ’ ์—ฐ๊ฒฐํ•˜๊ธฐ

ref={nameInputRef}, ref={ageInputRef}

<input
  id="username"
  type="text"
  // โœ… ref
  ref={nameInputRef}
  />

//...

<input
  id="age"
  type="number"
  // โœ… ref
  ref={ageInputRef}
  />
  • ๊ทธ๋Ÿฌ๋ฉด ๋ฆฌ์•กํŠธ๊ฐ€ ์ฝ”๋“œ์— ์ฒ˜์Œ ๋„๋‹ฌํ•ด์„œ ๋ชจ๋“œ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ, nameInputRef์™€ ageInputRef์— ์ €์žฅ๋œ ๊ฐ’์„ ์ด ์ธํ’‹์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ Œ๋”๋ง๋œ ๋„ค์ดํ‹ฐ๋ธŒ DOM ์š”์†Œ์— ์„ค์ •ํ•œ๋‹ค.
  • nameInputRef์™€ ageInputRef ์•ˆ์— ๋“  ๊ฐ’์€ ๋‚˜์ค‘์— Real DOM์˜ ์š”์†Œ๊ฐ€ ๋œ๋‹ค.

3. addUserHandler ํ•จ์ˆ˜ ์•ˆ์— ์ƒˆ๋กœ์šด ์ƒ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  ref์— ์ €์žฅ๋œ ํ˜„์žฌ input ๊ฐ’์„ ์ €์žฅํ•˜๊ณ , ์กฐ๊ฑด ๊ฐ’์— ์‚ฌ์šฉํ•œ ์ƒ์ˆ˜๋ฅผ state ๊ฐ’ ๋Œ€์‹  ref๋กœ ๊ฐ€์ ธ์˜จ ์ƒ์ˆ˜๋กœ ๋‹ค ๋ฐ”๊พธ๊ธฐ

const addUserHandler = (event) => {
    event.preventDefault();
    //โœ… 3. ์ƒ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  ref์— ์ €์žฅ๋œ ํ˜„์žฌ input ๊ฐ’ ์ €์žฅ
    // ์กฐ๊ฑด ๊ฐ’์— ์‚ฌ์šฉํ•œ ์ƒ์ˆ˜๋ฅผ state๋Œ€์‹  ref๋กœ ๊ฐ€์ ธ์˜จ ์ƒ์ˆ˜๋กœ ๋‹ค ๋ฐ”๊พผ๋‹ค.
    const enteredRefName = nameInputRef.current.value;
    const enteredRefAge = ageInputRef.current.value;

    if (
      enteredRefName.trim().length === 0 ||
      enteredRefAge.trim().length === 0
    ) {
      setError({
        title: "Invalid input",
        message: "Please enter a valid name and age (non-empty values).",
      });
      return;
    }
    if (+enteredRefAge < 1) {
      setError({
        title: "Invalid age",
        message: "Please enter a valid age (> 0).",
      });
      return;
    }
    props.onAddUser(enteredRefName, enteredRefAge);
    //...
  };

4. ์ž…๋ ฅ ํ›„ input ๊ฐ’ ์žฌ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด DOM ์กฐ์ž‘ํ•˜๊ธฐ

// โŒ setState ์‚ญ์ œ
// setEnteredUsername("");
// setEnteredAge("");

//โœ… 
nameInputRef.current.value = "";
ageInputRef.current.value = "";
  • ์ผ๋ฐ˜์ ์œผ๋กœ DOM์„ ์ง์ ‘ ์กฐ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š์ง€๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’ ์žฌ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒฝ์šฐ๋Š” ์‚ฌ์šฉํ•ด๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.
  • ์ด ๋ฐฉ๋ฒ•์€ ํ”ํžˆ ์“ฐ์ด๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋‹ˆ๋‹ค. DOM ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ref ์“ฐ๋Š” ๊ฒฝ์šฐ๋Š” ๋งค์šฐ ๋“œ๋ฌผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜๋„ ์—ฌ๊ธฐ์„œ ์ž ๊น ์“ฐ๋Š” ๊ฑด ๊ดœ์ฐฎ๋‹ค ^^..
  • ๋ฆฌ์•กํŠธ๋Š” state๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ปจํŠธ๋กคํ•˜๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ์ง์ ‘ DOM์„ ์กฐ์ž‘ํ•˜๋ฉด ๋ฆฌ์•กํŠธ๊ฐ€ ์ปจํŠธ๋กคํ•˜์ง€ ๋ชปํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ(Uncontrolled Component)๊ฐ€ ๋œ๋‹ค. ์ด๋Ÿฐ์‹์œผ๋กœ ์“ฐ๊ณ  ์‹ถ์ง€ ์•Š์œผ๋ฉด ์›๋ž˜ ์ž‘์„ฑํ–ˆ๋˜ ๋Œ€๋กœ state ๊ธฐ๋ฐ˜์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

โœ… ์ „์ฒด ์ฝ”๋“œ


import React, { useState, useRef } from "react";

import Card from "../UI/Card";
import Button from "../UI/Button";
import ErrorModal from "../UI/ErrorModal";
import classes from "./AddUser.module.css";

const AddUser = (props) => {
  //โœ… 1. useRef() ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ref ์ƒ์„ฑ
  // ์‚ฌ์šฉ์ž ์ด๋ฆ„ ์ž…๋ ฅํ•˜๋Š” ์ธํ’‹๊ณผ ์—ฐ๊ฒฐํ•  ref ์ƒ์„ฑ
  const nameInputRef = useRef();
  // ์‚ฌ์šฉ์ž ๋‚˜์ด ์ž…๋ ฅํ•˜๋Š” ์ธํ’‹๊ณผ ์—ฐ๊ฒฐํ•  ref ์ƒ์„ฑ
  const ageInputRef = useRef();

  //โŒ ์ด์ œ state ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ญ์ œ
  // const [enteredUsername, setEnteredUsername] = useState("");
  // const [enteredAge, setEnteredAge] = useState("");
  const [error, setError] = useState();

  const addUserHandler = (event) => {
    event.preventDefault();
    //โœ… 3. ์ƒ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  ref์— ์ €์žฅ๋œ ํ˜„์žฌ input ๊ฐ’ ์ €์žฅ
    // ์กฐ๊ฑด ๊ฐ’์— ์‚ฌ์šฉํ•œ ์ƒ์ˆ˜๋ฅผ state๋Œ€์‹  ref๋กœ ๊ฐ€์ ธ์˜จ ์ƒ์ˆ˜๋กœ ๋‹ค ๋ฐ”๊พผ๋‹ค.
    const enteredRefName = nameInputRef.current.value;
    const enteredRefAge = ageInputRef.current.value;

    if (
      enteredRefName.trim().length === 0 ||
      enteredRefAge.trim().length === 0
    ) {
      setError({
        title: "Invalid input",
        message: "Please enter a valid name and age (non-empty values).",
      });
      return;
    }
    if (+enteredRefAge < 1) {
      setError({
        title: "Invalid age",
        message: "Please enter a valid age (> 0).",
      });
      return;
    }
    props.onAddUser(enteredRefName, enteredRefAge);
    // โŒ setState ์‚ญ์ œ
    // setEnteredUsername("");
    // setEnteredAge("");

    //โœ… 4. ์ผ๋ฐ˜์ ์œผ๋กœ DOM์„ ์ง์ ‘ ์กฐ์ž‘ํ•˜๋ฉด ์•ˆ๋˜๊ธด ํ•œ๋ฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’ ์žฌ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒฝ์šฐ๋Š” ์‚ฌ์šฉํ•ด๋„ ๋ฌด๋ฐฉํ•˜์ง€๋งŒ ํ”ํžˆ ์“ฐ์ด๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋‹ˆ๋‹ค. DOM ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ref ์“ฐ๋Š” ๊ฒฝ์šฐ๋Š” ๋งค์šฐ ๋“œ๋ฌผ๊ธฐ ๋•Œ๋ฌธ! ๊ทผ๋ฐ ์—ฌ๊ธฐ์„  ์“ธ๊ฑฐ์ž„!
    nameInputRef.current.value = "";
    ageInputRef.current.value = "";
    //์ด๋ ‡๊ฒŒ ์•ˆ์“ฐ๊ณ  ์‹ถ์œผ๋ฉด state ๊ธฐ๋ฐ˜ ํ•ด๊ฒฐ๋ฒ• ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  };

  // โŒ state ๊ด€๋ จ๋œ ๋ถ€๋ถ„ ๋‹ค ์‚ญ์ œ
  // const usernameChangeHandler = (event) => {
  //   setEnteredUsername(event.target.value);
  
  //โ—๏ธ ref๋ฅผ ์ฝ˜์†”์— ์ฐ์–ด๋ณด๋ฉด current ๊ฐ’์ด id๊ฐ€ username์ธ input์ด ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  //console.log(nameInputRef);
  //console.log(nameInputRef.current.value);
  // };

  // const ageChangeHandler = (event) => {
  //   setEnteredAge(event.target.value);
  //  console.log(ageInputRef);
  // };
  
  const errorHandler = () => {
    setError(null);
  };

  //โœ… 2. ์—ฐ๊ฒฐํ•  JSX ์ฝ”๋“œ์— ref prop ์ถ”๊ฐ€ํ•˜์—ฌ ref ์—ฐ๊ฒฐํ•˜๊ธฐ
  //ref={nameInputRef}, ref={ageInputRef}
  return (
    <>
      {error && (
        <ErrorModal
          title={error.title}
          message={error.message}
          onConfirm={errorHandler}
        />
      )}
      <Card className={classes.input}>
        <form onSubmit={addUserHandler}>
          <label htmlFor="username">Username</label>
          <input
            id="username"
            type="text"
            // โŒ value={enteredUsername}
            // โŒ onChange={usernameChangeHandler}
            // โœ… ref
            ref={nameInputRef}
          />
          <label htmlFor="age">Age (Years)</label>
          <input
            id="age"
            type="number"
            // โŒ value={enteredAge}
            // โŒ onChange={ageChangeHandler}
            // โœ… ref
            ref={ageInputRef}
          />
          <Button type="submit">Add User</Button>
        </form>
      </Card>
    </>
  );
};

export default AddUser;

๐Ÿ”ฅ State vs Ref

state๋ฅผ ํ‚ค ๋กœ๊ทธ ๊ธฐ๋ก์šฉ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š”๊ฑด ๋ณ„๋กœ ์ข‹์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’๋งŒ ์ฝ๊ณ  ์‹ถ์ง€ ์•„๋ฌด ๊ฒƒ๋„ ๋ฐ”๊ฟ€ ๊ณ„ํš์ด ์—†๋‹ค๋ฉด ref๊ฐ€ ๋‚ซ๋‹ค.

  • ref
    ์ ์€ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
    ํ•˜์ง€๋งŒ DOM ์กฐ์ž‘ํ•œ๋‹ค๋Š” ์ƒ๋‹นํžˆ ์˜ˆ์™ธ์ ์ธ ์ผ์„ ํ•ด์•ผ ํ•จ
    ref ์‚ฌ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ๋Š” (๋ฆฌ์•กํŠธ์— ์˜ํ•ด)์ œ์–ด๋˜์ง€ ์•Š๋Š” ์ปดํฌ๋„ŒํŠธ

  • state
    ํ™•์‹คํžˆ ๋” ๊น”๋”ํ•จ
    ํ•˜์ง€๋งŒ ์ฝ”๋“œ๋ฅผ ref๋ณด๋‹ค ๋” ๋งŽ์ด ์จ์•ผ ํ•จ
    state ์‚ฌ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ๋Š” (๋ฆฌ์•กํŠธ์— ์˜ํ•ด)์ œ์–ด๋˜๋Š” ์ปดํฌ๋„ŒํŠธ

profile
Always have hope๐Ÿ€ & constant passion๐Ÿ”ฅ

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