๊ฐœ๋ฐœ ๐Ÿพ/ReactJS

React ์—์„œ useRef ์‚ฌ์šฉํ•˜๊ธฐ

JOTOKKI 2021. 6. 30. 14:25
728x90

์ฐธ์กฐ: https://ko.reactjs.org/docs/hooks-reference.html#useref

 

useRef๋Š” ์ƒ๊ฐ๋ณด๋‹ค ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. SPA์—์„œ๋Š” ๋ณ€ํ™”์— ๋”ฐ๋ฅธ ๋ Œ๋”๋ง์œผ๋กœ ๊ฐ์ฒด์— ์ง์ ‘ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. 

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— React์—์„œ๋Š” useRef hook์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. useRef๊ฐ€ ์ง์ ‘ ๊ฐ์ฒด์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ์ด์œ ๋Š” ๋งค๋ฒˆ ๋ Œ๋”๋ง์„ ํ•  ๋•Œ๋งˆ๋‹ค ๋™์ผํ•œ ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•œ๋‹ค๊ณ  ๊ณต์‹๋ฌธ์„œ์— ๋‚˜์™€์žˆ์Šต๋‹ˆ๋‹ค. 

 

๋ฐ˜๋ฉด, state์™€๋Š” ๋‹ฌ๋ฆฌ ์‹ค์‹œ๊ฐ„ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ๋ณ€ํ™”๋œ ๊ฐ’์„ ๋ฆฌํ„ดํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. 

์ด๊ฒŒ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด ref๋ฅผ ๋”ฐ๋กœ setStateํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

 

 

1. useRef๋ฅผ ํ†ตํ•œ timer๋งŒ๋“ค๊ธฐ

์ฐธ์กฐ : https://dmitripavlutin.com/react-useref-guide/

 

ํƒ€์ด๋จธ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ jsx๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

import { useState, useRef } from "react";

export default function UseRefSample1() {
  const countRef = useRef(null);
  const [Count, setCount] = useState(0);

  return (
    <div className="wrap">
        <h2>StopWatch ๋งŒ๋“ค๊ธฐ</h2>
        <div>
            <div className="timer">Timer: {Count}ms</div>
            <button>Start</button>
            <button>Stop</button>
            <button>Reset</button>
        </div>
    </div>
  );
}

countRef๋Š” setInterval์„ ๋‹ด๊ธฐ ์œ„ํ•จ์ด๊ณ  Count state๋Š” ์ดˆ ๋‹จ์œ„๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. 

๊ทธ๋ฆฌ๊ณ  ํƒ€์ด๋จธ ์‹œ์ž‘, ์ค‘์ง€, ๋ฆฌ์…‹ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

  const startHandler = () => {
    countRef.current = setInterval(() => setCount((c) => c + 1), 100);
  };

  const stopHandler = () => {
    clearInterval(countRef.current);
    countRef.current = null;
  };

  const resetHandler = () => {
    stopHandler();
    setCount(0);
  };

startHandler์—์„œ setInterval๋กœ ์ดˆ๋‹จ์œ„ Count์— setState ์‹œ์ผœ์ฃผ๊ณ  ํ•ด๋‹น setInterval์€ ref.current์— ๋‹ด๊ฒจ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— stopHandler์—์„œ ์‰ฝ๊ฒŒ clearInterval์„ ํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ startHandler๋ฅผ ํด๋ฆญํ•˜๋ฉด Count์˜ ๊ฐ’์€ ๋‚จ์•„์žˆ์œผ๋ฏ€๋กœ ๊ธฐ์กด ์นด์šดํŠธ๊ฐ€ ์Œ“์ธ ๊ฐ’์—์„œ ๋‹ค์‹œ 1์ดˆ๋งˆ๋‹ค ํ”Œ๋Ÿฌ์Šค๋˜๊ณ ,

resetHandler์—์„œ ์˜จ์ „ํ•œ ๋ฆฌ์…‹์„ ์œ„ํ•ด Count์˜ ๊ฐ’๋„ 0 ์ฒ˜๋ฆฌํ•ด์ค๋‹ˆ๋‹ค. 

 

๊ฒฐ๊ณผ

 

2. useRef๋ฅผ ํ†ตํ•ด input Focus ์ฃผ๊ธฐ

ํ”„๋กœ์ ํŠธ์— ์ž…๋ ฅํ•˜๋Š” form ์–‘์‹์— ๋นˆ ๊ฐ’ ์ฒดํฌ๋ฅผ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค๋ฉด ์ฒดํฌ ํ›„ ํ•ด๋‹น input์œผ๋กœ focus๋ฅผ ์ฃผ๋Š” ๊ธฐ๋Šฅ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

์šฐ์„  ๋งˆํฌ์—…์„ ํ•ด์ค๋‹ˆ๋‹ค.

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

export default function UseRefSample2() {
  const [Msg, setMsg] = useState(null);
  return (
    <div className="wrap">
      <h2>Input Focus</h2>
      <p>
        <input placeholder="Name" />
      </p>
      <p>
        <input placeholder="Age" />
      </p>
      <button>Submit</button>
      {
          Msg === null ? "" 
          : Msg ?  <div className="msg">๋ชจ๋‘ ์ž…๋ ฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!</div> 
          : <div className="msg warning">๋ชจ๋‘ ์ž…๋ ฅํ•˜์„ธ์š”!</div>
      }
    </div>
  );
}

๊ทธ๋ฆฌ๊ณ  input value์™€ state๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅ ์–‘์‹์ด ์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด ๊ฐ์ฒด ํƒ€์ž…์œผ๋กœ ํ•œ state์— ๋ฌถ๊ณ  name๊ฐ’์„ ํ‚ค๊ฐ’์œผ๋กœ ์ง€์ •ํ•˜์—ฌ onChange์‹œ ์ƒํƒœ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.

 

{...}
  const [Inputs, setInputs] = useState({
    name: "",
    age: ""
  });

  const handleChange = (e) => {
    setInputs({
      ...Inputs,
      [e.target.name]: e.target.value
    });
  };
{...}
      <p>
        <input
          placeholder="Name"
          name="name"
          value={Inputs.name}
          onChange={handleChange}
        />
      </p>
      <p>
        <input
          placeholder="Age"
          name="age"
          value={Inputs.age}
          onChange={handleChange}
        />
      </p>

 

๊ทธ๋ฆฌ๊ณ  ๋ชจ๋‘ ์ž…๋ ฅํ•œ ๋’ค ์ฒ˜๋ฆฌ๋˜๋Š” handleSubmit์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. 

์—ฌ๊ธฐ์„œ๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ Msg ๊ฐ’ ํ•˜๋‚˜๋ฅผ ๋‘์–ด null์ผ ๋•Œ๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ๋ณด์ด์ง€ ์•Š๊ณ , false์ผ ๋•Œ๋Š” "๋ชจ๋‘ ์ž…๋ ฅํ•˜์„ธ์š”!", true์ผ ๋•Œ๋Š” "๋ชจ๋‘ ์ž…๋ ฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."๋ผ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋„์›๋‹ˆ๋‹ค. 

์ด๋•Œ ๋นˆ ๊ฐ’ ์ฒดํฌ๋ฅผ ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ handleCheckForm ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋กœ ๋‘์–ด ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 

 

const handleSubmit = (e) => {
  if (handleCheckForm()) {
  	setMsg(true);
  } else {
  	setMsg(false);
  }
};
  
 const handleCheckForm = () => {
  if (Inputs.name === "") {
  	alert("์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”!");
  	return false;
  }
  if (Inputs.age === "") {
  	alert("๋‚˜์ด๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”!");
 	 return false;
  }
  return true;
};

  return (
    <div className="wrap">
      <h2>Input Focus</h2>
      { ... }
      <button onClick={handleSubmit}>Submit</button>
      {Msg === null ? (
        ""
      ) : Msg ? (
        <div className="msg">๋ชจ๋‘ ์ž…๋ ฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.</div>
      ) : (
        <div className="msg warning">๋ชจ๋‘ ์ž…๋ ฅํ•˜์„ธ์š”!</div>
      )}
    </div>
  );

name, age ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋นˆ ๊ฐ’์ด๋ฉด false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋‘˜ ๋‹ค ๋นˆ๊ฐ’์ด ์•„๋‹ˆ๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด์„œ setMsg๊ฐ€ true ํ˜น์€ false๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. 

๊ทธ๋Ÿฌ๋ฉด ๋‚˜๋จธ์ง€ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ๋“ค์„ useRef๋ฅผ ํ†ตํ•ด ์ฒ˜๋ฆฌํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 

 

1. submitํด๋ฆญ ์‹œ ๊ฐ’์ด ๋น„์–ด์žˆ๋Š” input์— ์ž๋™ focus๋ฅผ ํ•œ๋‹ค. 

2. name input์—์„œ Enter์‹œ ๋‹ค์Œ input์œผ๋กœ ์ด๋™, age input์—์„œ Enter์‹œ handleSubmit ํ˜ธ์ถœ 

 

๋จผ์ € useRef๋ฅผ ํ†ตํ•ด nameRef, ageRef๋ฅผ ์„ ์–ธํ•˜๊ณ  input์— ์—ฐ๊ฒฐ์‹œ์ผœ์ค๋‹ˆ๋‹ค. 

๊ฐ์ฒด ์ ‘๊ทผ์€ current๋ฅผ ํ†ตํ•ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

ํ•ด๋‹น ref๋ฅผ console๋กœ ์กฐํšŒํ•ด๋ณด๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ ๋งŽ์€ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

 

ref ์กฐํšŒ ๊ฒฐ๊ณผ

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

const nameRef = useRef(null);
const ageRef = useRef(null);

// Enter์‹œ age input์œผ๋กœ focus
const handleNextInput = (e) => {
    if (e.key === "Enter") {
        ageRef.current.focus();
    }
};

// Enter์‹œ handleSubmit ํ˜ธ์ถœ
const handleChangeSubmit = (e) => {
    if (e.key === "Enter") handleSubmit();
};

// ์ตœ์ดˆ ํŽ˜์ด์ง€ ์ง„์ž…์‹œ name input์— focus
useEffect(() => {
    nameRef.current.focus();
}, []);

{...}

<p>
    <input
        placeholder="Name"
        name="name"
        value={Inputs.name}
        ref={nameRef}
        onChange={handleChange}
        onKeyPress={handleNextInput} 
    />
</p>
<p>
    <input
        placeholder="Age"
        name="age"
        value={Inputs.age}
        ref={ageRef}
        onChange={handleChange}
        onKeyPress={handleChangeSubmit}
    />
</p>

 

 

์ด ์™ธ์— useRef๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ๊ฒƒ๋“ค์„ ์‚ดํŽด๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด ํ•ด๋‹น ๊ธ€๋„ ํ™•์ธํ•ด๋ณด์„ธ์š”. 

 

React div ์Šคํฌ๋กค์‹œ Fix ํ•˜๊ธฐ (Element scroll)

react draggable ๊ฐ„๋‹จ ์ƒ˜ํ”Œ

React ์—์„œ ์• ๋‹ˆ๋ฉ”์ด์…˜, ์ธํ„ฐ๋ ‰์…˜ ๊ตฌ์ถ•ํ•˜๊ธฐ (emotion / tweenmax)

๋ฐ˜์‘ํ˜•