๐Ÿ”ฅ [React] useEffect(): ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ๋Œ€์ฒ˜ํ•˜๊ธฐ

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

React JS

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

๐Ÿ“ Effects(= Side Effects)๋ž€?

๋ฆฌ์•กํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ฃผ์š”ํ•œ ์ž„๋ฌด๋Š” UI๋ฅผ ๋ Œ๋”๋ง ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰, ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋ฐ˜์‘ํ•˜์—ฌ ํ•„์š”ํ•  ๋•Œ UI๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์ด ๋ฆฌ์•กํŠธ์˜ ์ผ์ด๋‹ค.
์ปดํฌ๋„ŒํŠธ๋Š” ๋‹จ์ง€ ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์œ„์—์„œ ๋ถ€ํ„ฐ ์•„๋ž˜๋กœ ์‹คํ–‰๋˜๋Š”๋ฐ, ๊ฒฐ๊ตญ์—๋Š” ํ™”๋ฉด์— ๋ฌด์–ธ๊ฐ€ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ํ•จ์ˆ˜๊ฐ€ ํ•˜๋Š” ์ผ์˜ ์ „๋ถ€์ด๋‹ค.

  • ์˜ˆ์‹œ
    • ๋ฒ„ํŠผ ํด๋ฆญ
    • ํ…์ŠคํŠธ ์ž…๋ ฅ
  • ๋ฆฌ์•กํŠธ๋Š” JSX์ฝ”๋“œ๋ฅผ ํ‰๊ฐ€ํ•˜๊ณ  ๋ Œ๋”๋งํ•œ๋‹ค.
  • ๋˜ํ•œ state์™€ props์„ ๊ด€๋ฆฌํ•˜๊ณ , ํด๋ฆญ-์ž…๋ ฅ ๋“ฑ์˜ ์‚ฌ์šฉ์ž ์ด๋ฒคํŠธ์™€ ์ž…๋ ฅ์— ๋ฐ˜์‘ํ•˜์—ฌ state์™€ prop์˜ ๋ณ€๊ฒฝ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌํ‰๊ฐ€ํ•˜์—ฌ ๋ Œ๋”๋งํ•œ๋‹ค.
  • ๋”ฐ๋ผ์„œ ๋ฆฌ์•กํŠธ์˜ ์ฃผ์š” ์ž„๋ฌด๋Š” useState() ํ›…๊ณผ props๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฒ˜๋ฆฌํ–ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์ดํŽ™ํŠธ(=์‚ฌ์ดํŠธ ์ดํŽ™ํŠธ)๋ž€ ๋ฌด์—‡์ผ๊นŒ?
๋ฐ”๋กœ ํ™”๋ฉด์— ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ์ผ์ด ์•„๋‹Œ ๋ชจ๋“  ์ผ, ์ฆ‰ ์•ฑ์—์„œ ์ผ์–ด๋‚˜๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

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

โœ… useEffect() ํ›…

useEffect() ํ›…์€ ๋ฆฌ์•กํŠธ ๋‚ด์žฅ ํ›…์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŠน๋ณ„ํ•œ ์ผ์„ ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. useEffect()ํ›…์„ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

useEffect()์˜ 2๊ฐ€์ง€ ์ธ์ž

useEffect(() => {...}, [ dependencies ]);
  • ์ฒซ ๋ฒˆ์งธ ์ธ์ž: ํ•จ์ˆ˜
    ์ง€์ •๋œ ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ์—๋งŒ, ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ํ‰๊ฐ€ ํ›„์— ์‹คํ–‰๋˜๋Š” ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
    ๋”ฐ๋ผ์„œ ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.
  • ์˜์กด์„ฑ ๋ฐฐ์—ด(๋””ํŽœ๋˜์‹œ ๋ฐฐ์—ด)
    ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋ณ€๊ฒฝ๋  ๋•Œ์—๋งŒ ์ฒซ ๋ฒˆ์งธ ์ธ์ž์ธ ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋””ํŽœ๋˜์‹œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

useEffect()๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌดํ•œ ๋ฃจํ”„์— ๋น ์ง€์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

1. ๋””ํŽœ๋˜์‹œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ: (์˜ˆ์‹œ) ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€ ์ด์šฉํ•œ ๋กœ๊ทธ์ธ ์œ ์ง€ํ•˜๊ธฐ

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ ํ›„, ์ƒˆ๋กœ๊ณ ์นจ์ด ๋˜์–ด๋„ ๋กœ๊ทธ์ธ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ํ‚ค-๊ฐ’ ์‹๋ณ„์ž๋ฅผ ์ €์žฅํ•˜์—ฌ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์‹๋ณ„์ž๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋กœ๊ทธ์ธ์ด ์œ ์ง€๋˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด์ž.

import React, { useState } from 'react';

import Login from './components/Login/Login';
import Home from './components/Home/Home';
import MainHeader from './components/MainHeader/MainHeader';

function App() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const loginHandler = (email, password) => {
    // We should of course check email and password
    // But it's just a dummy/ demo anyways
    setIsLoggedIn(true);
  };

  const logoutHandler = () => {
    setIsLoggedIn(false);
  };

  return (
    <React.Fragment>
      <MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
      <main>
        {!isLoggedIn && <Login onLogin={loginHandler} />}
        {isLoggedIn && <Home onLogout={logoutHandler} />}
      </main>
    </React.Fragment>
  );
}

export default App;

1. localStorage์— ํ‚ค-๊ฐ’ ์ €์žฅํ•˜๊ธฐ

์•ฑ์ด ์‹œ์ž‘ํ•  ๋•Œ ๋งˆ๋‹ค (๋กœ๊ทธ์ธ)๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ง€๋˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ์ž‘์—…์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋จผ์ € ๋ธŒ๋ผ์šฐ์ € ์ €์žฅ์†Œ(๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€/์ฟ ํ‚ค)์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ด์•ผ ํ•œ๋‹ค.

๋ธŒ๋ผ์šฐ์ €์— ๋‚ด์žฅ๋œ ์ €์žฅ ๋งค์ปค๋‹ˆ์ฆ˜์ธ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋Š” ๋ฆฌ์•กํŠธ์™€ ์•„๋ฌด ์ƒ๊ด€์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์žˆ๋Š” loginHandler ํ•จ์ˆ˜์—์„œ ๋ถˆ๋Ÿฌ์™€์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • localStorage.setItem("์‹๋ณ„์ž", "์‹๋ณ„์ž");
    setItem()์€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ „์—ญ ๊ฐ์ฒด์ด๋‹ค.
 const loginHandler = (email, password) => {
    // We should of course check email and password
    // But it's just a dummy/ demo anyways

    //๋กœ๊ทธ์ธ ํ–ˆ์œผ๋ฉด 1, ๋กœ๊ทธ์ธ ์•ˆ ํ–ˆ์œผ๋ฉด 0์œผ๋กœ ์‹๋ณ„
    localStorage.setItem("isLoggedIn", "1");
    setIsLoggedIn(true);
  };
  • ๊ทธ๋Ÿฌ๋ฉด ์ด๋Ÿฐ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋œ๋‹ค.

loginHandler ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ๋งŒ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ž์ฃผ ์ผ์–ด๋‚˜๋Š” ์ผ์€ ์•„๋‹ˆ๊ณ , ๋ญ”๊ฐ€ ์ €์žฅํ•˜๊ณ  ์‹ถ์„ ๋•Œ(๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์ด ํด๋ฆญ๋  ๋•Œ)๋งŒ ์‹คํ–‰๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๊ฒฝ์šฐ์—๋Š” useEffect๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•˜์ง€๋Š” ์•Š๋‹ค.

ํ•˜์ง€๋งŒ ์•ฑ์ด ๋‹ค์‹œ ์‹œ์ž‘๋˜๋Š” ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋– ๋‚ฌ๋‹ค๊ฐ€ ๋‹ค์‹œ ๋Œ์•„์˜ค๋Š” ๊ฒฝ์šฐ, ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•  ๊ฒฝ์šฐ์—๋Š” ์–ด๋–จ๊นŒ?
๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์—๋Š” ํ‚ค-๊ฐ’ ์Œ์ด ๋‚จ์•„์žˆ๋”๋ผ๋„ ์ƒˆ๋กœ๊ณ ์นจํ•˜๋ฉด, ์ฆ‰ ์•ฑ์ด ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋ฉด App ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋Š” ๋‹ค์‹œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋กœ๊ทธ์ธ์€ ํ’€๋ ค ๋ฒ„๋ฆฐ๋‹ค.

2. ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์—์„œ ์‹๋ณ„์ž ํ™•์ธํ•˜์—ฌ ๋กœ๊ทธ์ธ ์œ ์ง€ํ•˜๊ธฐ

๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์ง€ ์•Š์•„๋„, ์ฆ‰ loginHandler๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ ๋˜์ง€ ์•Š์•„๋„ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— isLoggedIn์˜ ๊ฐ’์ด 1์ธ ๊ฒฝ์šฐ์—๋Š” ๋กœ๊ทธ์ธ์ด ์œ ์ง€๋˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด, ์กฐ๊ฑดํ•จ์ˆ˜๋ฅผ ๊ฑธ์–ด state๋ฅผ true๋กœ ๋ณ€๊ฒฝํ•ด ์ฃผ์ž.

function App() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญํ•˜์ง€ ์•Š์•„๋„, ์ฆ‰ loginHandler๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ ๋˜์ง€ ์•Š์•„๋„ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— isLoggedIn์˜ ๊ฐ’์ด 1์ธ ๊ฒฝ์šฐ์—๋Š” ๋กœ๊ทธ์ธ ์œ ์ง€ํ•˜๊ธฐ
  const storedUserLoggedInInformation = localStorage.getItem("isLoggedIn");
    if (storedUserLoggedInInformation === "1") {
      setIsLoggedIn(true);
    }
  
 //...

๊ทธ๋Ÿฐ๋ฐ ์ด๋ ‡๊ฒŒ๋งŒ ํ•˜๋ฉด ๋ฌดํ•œ ๋ฃจํ”„์— ๋น ์งˆ ์ˆ˜๊ฐ€ ์žˆ๋‹ค.

  • isLoggedIn์ด 1๋กœ ์ €์žฅ๋˜์–ด ์žˆ๋Š”์ง€ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ํ™•์ธ
  • ์ €์žฅ๋˜์–ด ์žˆ์œผ๋ฉด setState๋กœ true๋กœ ์„ค์ •
  • ๊ทธ๋ฆฌ๊ณ  setState ํ•จ์ˆ˜ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค App์ปดํฌ๋„ŒํŠธ ๋‹ค์‹œ ์‹คํ–‰
  • ๊ทธ๋Ÿฌ๋ฉด ๋˜ ๋‹ค์‹œ ์‹คํ–‰๋˜๊ณ  1์ด ๋‚˜์˜ค๋ฉด ๋˜ setState
  • ๋ฐ˜๋ณต ๋ฐ˜๋ณต ๋ฌดํ•œ ๋ฐ˜๋ณต ๐ŸŒ€๐Ÿ˜ต๐ŸŒ€

์ด๋Ÿด ๋•Œ useEffect()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ธ์ œ ์ด ์‚ฌ์ด๋“œ์ดํŽ™ํŠธ๋ฅผ ์‹คํ–‰ํ• ์ง€ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

3. useEffect() ์‚ฌ์šฉํ•˜์—ฌ ๋ฌดํ•œ๋ฃจํ”„ ํƒˆ์ถœํ•˜๊ธฐ

function App() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญํ•˜์ง€ ์•Š์•„๋„-์ฆ‰ loginHandler๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ ๋˜์ง€ ์•Š์•„๋„, ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— isLoggedIn์˜ ๊ฐ’์ด 1์ธ ๊ฒฝ์šฐ์—๋Š” ๋กœ๊ทธ์ธ ์œ ์ง€ํ•˜๊ธฐ
  //๋ฌดํ•œ ๋ฃจํ”„ ๋ฐฉ์ง€ ์œ„ํ•ด useEffect ์‚ฌ์šฉ
  useEffect(() => {
    const storedUserLoggedInInformation = localStorage.getItem("isLoggedIn");
    if (storedUserLoggedInInformation === "1") {
      setIsLoggedIn(true);
    }
  }, []);
//...
  • ์•ฑ์ด ์ฒ˜์Œ ์‹คํ–‰๋  ๋•Œ ์ดํŽ™ํŠธ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š”๋ฐ setStateํ•จ์ˆ˜๋กœ ์ธํ•ด ๋‹ค์‹œ App์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋œ๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฉด JSX ์ฝ”๋“œ๊ฐ€ ํ‰๊ฐ€๋˜๊ณ , DOM์€ ๊ทธ์— ๋”ฐ๋ผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.
  • ๊ทธ ํ›„ ์ดํŽ™ํŠธ๊ฐ€ ์žฌ์‹คํ–‰๋  ์ฐจ๋ก€์ธ๋ฐ, ๋””ํŽœ๋˜์‹œ๊ฐ€ ๋ฐ”๋€๊ฒŒ ์—†์œผ๋ฉด ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

์ฆ‰, ๋””ํŽœ๋˜์‹œ๊ฐ€ ๋น„์–ด ์žˆ๋Š” ๊ฒฝ์šฐ, ์˜์กด์„ฑ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์•ฑ์ด ์ฒ˜์Œ ์‹œ์ž‘๋˜๋ฉด ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋˜์–ด ์ดํŽ™ํŠธ ์ฝ”๋“œ๋Š” ์•ฑ์ด ์‹œ์ž‘๋  ๋•Œ ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋œ๋‹ค.

์ด์ œ useEffect ํ•จ์ˆ˜ ์•ˆ์— ์ดํŽ™ํŠธ ์ฝ”๋“œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์•กํŠธ์— ์˜ํ•ด ์‹คํ–‰๋˜๋ฏ€๋กœ ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ์—๋งŒ, ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ์žฌํ‰๊ฐ€ ํ›„์—, useEffect ์•ˆ์— ๋“  ์ดํŽ™ํŠธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

  • ์žฌํ‰๊ฐ€ ํ›„์— ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์ด ์•„์ฃผ ์ค‘์š”ํ•œ ํฌ์ธํŠธ์ด๋‹ค.
  • ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ ๋œ ๊ฒฝ์šฐ๋งŒ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ๋„ ์•„์ฃผ ์ค‘์š”ํ•œ ํฌ์ธํŠธ์ด๋‹ค.

์ด ์ฒ˜๋Ÿผ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ์™€ ๊ฐ™์€ ์ผ์€ ๋ฆฌ์•กํŠธ์˜ ์ฃผ๋œ ์ž„๋ฌด์ธ ํ™”๋ฉด ๊ทธ๋ฆฌ๊ธฐ๊ฐ€ ์•„๋‹Œ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ์ด๋‹ค. ๋ฌผ๋ก  ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„์—๋Š” UI๊ฐ€ ๋ฐ”๋€Œ๊ธด ํ•˜์ง€๋งŒ ๋ง์ด๋‹ค.

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

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

import Login from "./components/Login/Login";
import Home from "./components/Home/Home";
import MainHeader from "./components/MainHeader/MainHeader";

function App() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญํ•˜์ง€ ์•Š์•„๋„ ์ฆ‰ loginHandler๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ ๋˜์ง€ ์•Š์•„๋„, ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— isLoggedIn์˜ ๊ฐ’์ด 1์ธ ๊ฒฝ์šฐ์—๋Š” ๋กœ๊ทธ์ธ ์œ ์ง€ํ•˜๊ธฐ
  useEffect(() => {
    const storedUserLoggedInInformation = localStorage.getItem("isLoggedIn");
    if (storedUserLoggedInInformation === "1") {
      setIsLoggedIn(true);
    }
  }, []);
  //๋””ํŽœ๋˜์‹œ๊ฐ€ ๋น„์–ด ์žˆ๋Š” ๊ฒฝ์šฐ, ์˜์กด์„ฑ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์•ฑ์ด ์ฒ˜์Œ ์‹œ์ž‘๋˜๋ฉด ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋˜์–ด ์•ฑ์ด ์‹œ์ž‘๋  ๋•Œ ์ดํŽ™ํŠธ ์ฝ”๋“œ๋Š” ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋จ

  const loginHandler = (email, password) => {
    // We should of course check email and password
    // But it's just a dummy/ demo anyways
    
    //๋ธŒ๋ผ์šฐ์ € ์ €์žฅ์†Œ(๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€/์ฟ ํ‚ค)์— ์ •๋ณด ์ €์žฅํ•ด์„œ, ์•ฑ ์‹œ์ž‘ํ•  ๋•Œ ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ ์œ ์ง€๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
    //๋กœ๊ทธ์ธ ํ–ˆ์œผ๋ฉด 1, ๋กœ๊ทธ์ธ ์•ˆ ํ–ˆ์œผ๋ฉด 0์œผ๋กœ ์‹๋ณ„
    localStorage.setItem("isLoggedIn", "1");
    setIsLoggedIn(true);
  };

  const logoutHandler = () => {
    //๋กœ๊ทธ์•„์›ƒ์‹œ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— isLoggedIn ์—†์• ๊ธฐ
    localStorage.removeItem("isLoggedIn");
    setIsLoggedIn(false);
  };

  return (
    <React.Fragment>
      <MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
      <main>
        {!isLoggedIn && <Login onLogin={loginHandler} />}
        {isLoggedIn && <Home onLogout={logoutHandler} />}
      </main>
    </React.Fragment>
  );
}

export default App;

2. ๋””ํŽœ๋˜์‹œ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ

๊ฐ€๋” ๋””ํŽœ๋˜์‹œ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ดํŽ™ํŠธ ํ•จ์ˆ˜๋ฅผ ์•ฑ์ด ์‹œ์ž‘๋  ๋•Œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ์—ฌ๋Ÿฌ๋ฒˆ ์‹คํ–‰ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ๋””ํŽœ๋˜์‹œ๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋””ํŽœ๋˜์‹œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ useEffect๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž.

import React, { useState } from 'react';

import Card from '../UI/Card/Card';
import classes from './Login.module.css';
import Button from '../UI/Button/Button';

const Login = (props) => {
  const [enteredEmail, setEnteredEmail] = useState('');
  const [emailIsValid, setEmailIsValid] = useState();
  const [enteredPassword, setEnteredPassword] = useState('');
  const [passwordIsValid, setPasswordIsValid] = useState();
  const [formIsValid, setFormIsValid] = useState(false);

  const emailChangeHandler = (event) => {
    setEnteredEmail(event.target.value);
    //๐ŸŒ€ ๊ฐ™์€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
    setFormIsValid(
      event.target.value.includes('@') && enteredPassword.trim().length > 6
    );
  };

  const passwordChangeHandler = (event) => {
    setEnteredPassword(event.target.value);
    //๐ŸŒ€ ๊ฐ™์€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
    setFormIsValid(
      event.target.value.trim().length > 6 && enteredEmail.includes('@')
    );
  };

  const validateEmailHandler = () => {
    setEmailIsValid(enteredEmail.includes('@'));
  };

  const validatePasswordHandler = () => {
    setPasswordIsValid(enteredPassword.trim().length > 6);
  };

  const submitHandler = (event) => {
    event.preventDefault();
    props.onLogin(enteredEmail, enteredPassword);
  };

  return (
    <Card className={classes.login}>
      <form onSubmit={submitHandler}>
        <div
          className={`${classes.control} ${
            emailIsValid === false ? classes.invalid : ''
          }`}
        >
          <label htmlFor="email">E-Mail</label>
          <input
            type="email"
            id="email"
            value={enteredEmail}
            onChange={emailChangeHandler}
            onBlur={validateEmailHandler}
          />
        </div>
        <div
          className={`${classes.control} ${
            passwordIsValid === false ? classes.invalid : ''
          }`}
        >
          <label htmlFor="password">Password</label>
          <input
            type="password"
            id="password"
            value={enteredPassword}
            onChange={passwordChangeHandler}
            onBlur={validatePasswordHandler}
          />
        </div>
        <div className={classes.actions}>
          <Button type="submit" className={classes.btn} disabled={!formIsValid}>
            Login
          </Button>
        </div>
      </form>
    </Card>
  );
};

export default Login;

ํ˜„์žฌ ์œ„ ์ฝ”๋“œ์—์„œ๋Š” ์ด๋ฉ”์ผ/๋น„๋ฐ€๋ฒˆํ˜ธ ํ‚ค ๊ฐ’์ด ์ž…๋ ฅ๋  ๋•Œ๋งˆ๋‹ค ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๊ฐ™์€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋กœ์ง์„ ๋‘ ํ•ธ๋“ค๋Ÿฌ์— ๊ฐ๊ฐ ์ž‘์„ฑํ•ด์„œ ์‹คํ–‰ํ•˜๊ณ  ์žˆ๋‹ค.

์ด ๋กœ์ง์„ ํ•ฉ์ณ๋ณด์ž. ๋กœ๊ทธ์ธ ์ปดํฌ๋„ŒํŠธ ๋‚ด์— useEffect()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ๋กœ์ง์œผ๋กœ form์ด ์œ ํšจํ•œ์ง€ ๊ฒ€์‚ฌํ•˜๋Š” ๋กœ์ง์„ ์ดํŽ™ํŠธ ์ฝ”๋“œ๋กœ ๋„ฃ์œผ๋ฉด ๋œ๋‹ค.

useEffect(() => {
  setFormIsValid(
    enteredEmail.includes("@") && enteredPassword.trim().length > 6
  );
}, [enteredEmail, enteredPassword]);

์ด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋Š” ์ด๋ฉ”์ผ์ด๋‚˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ํŠธ๋ฆฌ๊ฑฐ ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋””ํŽœ๋˜์‹œ์— ์ž…๋ ฅ๋œ ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ state ๊ฐ’์„ ๋„ฃ์–ด์•ผ ํ•œ๋‹ค.
๋””ํŽœ๋˜์‹œ์— ์ด ๊ฐ’์„ ๋„ฃ์–ด์•ผ, ์ด๋ฉ”์ผ/๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ํ•ธ๋“ค๋Ÿฌ์˜ ๋ชจ๋“  ํ‚ค ์ž…๋ ฅ์— ๋Œ€ํ•ด์„œ ๊ณ„์†ํ•ด์„œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ๋Œ๋ฆด ์ˆ˜ ์žˆ๊ณ  ๋ฒ„ํŠผ์ด ์œ ํšจํ•˜๊ฒŒ ์ž‘๋™ํ•œ๋‹ค.

โœ… ์˜์กด์„ฑ ๋ฐฐ์—ด ์ž์ฒด๋ฅผ ์‚ญ์ œํ•ด๋ฒ„๋ฆฌ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

์˜์กด์„ฑ์ด ์—†์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ดํŽ™ํŠธ ์ฝ”๋“œ๋ฅผ ๊ทธ๋ƒฅ ์Œฉ์œผ๋กœ Login ํ•จ์ˆ˜ ์•ˆ์— ๋„ฃ์–ด๋ฒ„๋ฆฐ ๊ฒฉ์ด ๋˜์–ด๋ฒ„๋ฆฐ๋‹ค.
๊ทธ๋Ÿฌ๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ์ดํŽ™ํŠธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜์–ด ๋ฒ„๋ฆฌ๋ฏ€๋กœ ๊ณ„์† setFormIsValid๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์žฌ๋ Œ๋”๋ง ์ฃผ๊ธฐ ์ž์ฒด๋ฅผ ๊ณ„์† ํŠธ๋ฆฌ๊ฑฐํ•ด๋ฒ„๋ฆฌ๋ฏ€๋กœ ๋ฌดํ•œ๋ฃจํ”„ ์ถฉ๋Œ์ด ์ผ์–ด๋‚œ๋‹ค. ๐Ÿ˜ต

โœ… ๋ฌด์—‡์„ ๋””ํŽœ๋˜์‹œ๋กœ ๋„ฃ์–ด์•ผ ํ• ๊นŒ?

๊ฐ„๋‹จํ•œ ๊ทœ์น™์ด ์žˆ๋‹ค. ๋ฐ”๋กœ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์˜์กด์„ฑ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ ๋‚ด์šฉ์ด ๋ฐ”๋€” ๋•Œ๋งŒ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ์ œ์–ดํ•˜๋ฉด ๋œ๋‹ค.

  • ์—ฌ๊ธฐ์„œ๋Š” setFormIsValid, enteredEmail, enteredPassword๋ฅผ ๋””ํŽœ๋˜์‹œ์— ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.
    => ๋ชจ๋“  ๋กœ๊ทธ์ธ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ์‹คํ–‰ํ•œ ํ›„, ์ด useEffect ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ์‹คํ–‰์‹œ์ผœ๋ผ. setFormIsValid ๋˜๋Š” enteredEmail ๋˜๋Š” enteredPassword๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ์—๋งŒ!

  • ๐ŸŒŸ ๊ทธ๋Ÿฐ๋ฐ setFormIsValid๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค. ์™œ๋ƒํ•˜๋ฉด state ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฆฌ์•กํŠธ์— ์˜ํ•ด ์ ˆ๋Œ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋„๋ก ๋ณด์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
    ๋”ฐ๋ผ์„œ ์ด๋Ÿฐ setState ํ•จ์ˆ˜๋“ค์€ ์žฌ๋ Œ๋”๋ง ์ฃผ๊ธฐ์— ๋”ฐ๋ผ ๋ณ€ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ๋””ํŽœ๋˜์‹œ์— ์ƒ๋žตํ•ด๋„ ๋œ๋‹ค.

  • enteredEmail, enteredPassword๋Š” ๋ฐ”๋€” ์ˆ˜ ์žˆ๋Š” ๊ฐ’์ด๋‹ค. ํ‚ค๋ฅผ ๋ˆ„๋ฅผ ๋•Œ ๋งˆ๋‹ค ๋ณ€๊ฒฝ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋””ํŽœ๋˜์‹œ์— ๋„ฃ์–ด์•ผ ํ•œ๋‹ค.

โœ… ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ useEffect()

์ด๋ ‡๊ฒŒ ์ผ๋ฐ˜์ ์œผ๋กœ ํŠน์ • ๋ฐ์ดํ„ฐ(state๋‚˜ prop)๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋กœ์ง์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ useEffect๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์—ฅ ๊ทผ๋ฐ ์ด๊ฒŒ ์‚ฌ์ด๋“œ์ดํŽ™ํŠธ๋ผ๊ณ ? http ๋ฆฌํ€˜์ŠคํŠธ ๋ฐ›๊ฑฐ๋‚˜ ํƒ€์ด๋จธ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ํ•˜๋Š”๊ฒŒ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์•„๋‹ˆ์•ผ? ๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ธฐ์–ตํ•˜์ž! useEffect์˜ ์ฃผ์š” ์ž„๋ฌด๋Š” ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

  • ๋ณดํ†ต ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ผ๊ณ  ํ•˜๋ฉด http ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ๋งŽ์ด ๋– ์˜ฌ๋ฆฌ์ง€๋งŒ
  • ์œ„์˜ ์˜ˆ์ฒ˜๋Ÿผ ํ‚ค ์ž…๋ ฅ์„ ๋ฐ›์•„ ์ž…๋ ฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒƒ
  • ๊ทธ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ๋‹ค๋ฅธ ์•ก์…˜์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ ๋“ฑ๋„ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ์ด๋‹ค.
  • ์ฆ‰, ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•„๋“œ์˜ ํ‚ค ์ž…๋ ฅ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ํ•ด๋‹น ํผ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ๋„ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๋ฐ์ดํ„ฐ์˜ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ์ด๋‹ค.

useEffect๋Š” ๋ฌด์–ธ๊ฐ€(๋กœ๋“œ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ/์—…๋ฐ์ดํŠธ ๋˜๋Š” ์ด๋ฉ”์ผ ์ฃผ์†Œ ๋“ฑ)์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฃจ๋Š”๋ฐ ๋„์›€์ด ๋œ๋‹ค.

์ฆ‰, ๐ŸŒŸ ์–ด๋–ค ์•ก์…˜์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ์‹คํ–‰๋˜๋Š” ์•ก์…˜์€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— useEffect๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ ์ ˆํžˆ ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.


3. ๋””ํŽœ๋˜์‹œ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ vs ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ

๋””ํŽœ๋˜์‹œ์—๋Š” effect ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉํ•˜๋Š” "๋ชจ๋“  ๊ฒƒ"(๋ชจ๋“  ์ƒํƒœ ๋ณ€์ˆ˜์™€ ํ•จ์ˆ˜)์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์™ธ๊ฐ€ ์žˆ๋‹ค.

  • ์ƒํƒœ ์—…๋ฐ์ดํŠธ ๊ธฐ๋Šฅ setState๋Š” ๋””ํŽœ๋˜์‹œ๋กœ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
    React๋Š” ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์ ˆ๋Œ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•œ๋‹ค.

  • "๋‚ด์žฅ" API ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋””ํŽœ๋˜์‹œ๋กœ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
    fetch(), localStorage์™€ ๊ฐ™์ด ๋ธŒ๋ผ์šฐ์ €์— ๋‚ด์žฅ๋œ ํ•จ์ˆ˜ ๋ฐ ๊ธฐ๋Šฅ์€ ์ „์—ญ์ ์œผ๋กœ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ๋ฐ, ์ด๋Ÿฌํ•œ ๋ธŒ๋ผ์šฐ์ € API/์ „์—ญ ๊ธฐ๋Šฅ์€ React ๊ตฌ์„ฑ ์š”์†Œ ๋ Œ๋”๋ง ์ฃผ๊ธฐ์™€ ๊ด€๋ จ์ด ์—†์œผ๋ฉฐ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.

  • ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์—์„œ ์ •์˜๋œ ๋ณ€์ˆ˜๋‚˜ ํ•จ์ˆ˜(์˜ˆ: ๋ณ„๋„์˜ ํŒŒ์ผ์— ์ƒˆ ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“  ๊ฒฝ์šฐ)๋Š” ๋””ํŽœ๋˜์‹œ๋กœ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
    ํ•จ์ˆ˜ ๋˜๋Š” ๋ณ€์ˆ˜๊ฐ€ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์ƒ์„ฑ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€๊ฒฝํ•ด๋„ ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค. ํ•ด๋‹น ๋ณ€์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ, ๋˜๋Š” ๊ทธ ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ์—๋„ ์ปดํฌ๋„ŒํŠธ๋Š” ์žฌํ‰๊ฐ€๋˜์ง€ ์•Š๋Š”๋‹ค.

๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ effect ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  "๊ฒƒ๋“ค"์„ ๋””ํŽœ๋˜์‹œ๋กœ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜์ง€๋งŒ, ์ปดํฌ๋„ŒํŠธ(๋˜๋Š” ์ผ๋ถ€ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ)๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง ๋˜์–ด ์ด๋Ÿฌํ•œ "๊ฒƒ๋“ค"์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋””ํŽœ๋˜์‹œ๋กœ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

์ฆ‰, ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์— ์ •์˜๋œ ๋ณ€์ˆ˜๋‚˜ ์ƒํƒœ, ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์— ์ •์˜๋œ props ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋””ํŽœ๋˜์‹œ๋กœ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

์˜ˆ์‹œ ์ฝ”๋“œ

import { useEffect, useState } from 'react';
 
let myTimer;
 
const MyComponent = (props) => {
  const [timerIsActive, setTimerIsActive] = useState(false);
 
  const { timerDuration } = props; // using destructuring to pull out specific props values
 
  useEffect(() => {
    if (!timerIsActive) {
      setTimerIsActive(true);
      myTimer = setTimeout(() => {
        setTimerIsActive(false);
      }, timerDuration);
    }
  }, [timerIsActive, timerDuration]);
};

์œ„ ์ฝ”๋“œ์—์„œ

  • timerIsActive๋Š” โœ… ์ข…์†์„ฑ์œผ๋กœ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.
    ์™œ๋ƒํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ์˜ state ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค(์˜ˆ: ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์—).

  • timerDuration์€ โœ… ์ข…์†์„ฑ์œผ๋กœ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.
    ์™œ๋ƒํ•˜๋ฉด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ prop ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•ด๋‹น prop ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ฉด ํ•˜์œ„ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด MyComponent ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค์‹œ ๋ Œ๋”๋ง ๋œ๋‹ค.

  • setTimerIsActive๋Š” โŒ ์ข…์†์„ฑ์œผ๋กœ ์ถ”๊ฐ€๋˜์ง€ ์•Š๋Š”๋‹ค.
    ์™œ๋ƒํ•˜๋ฉด ์˜ˆ์™ธ ์กฐ๊ฑด์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. setState์— ๋Œ€ํ•ด React๊ฐ€ ์ ˆ๋Œ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Œ์„ ๋ณด์žฅํ•˜๋ฏ€๋กœ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

  • myTimer๋Š” โŒ ์ข…์†์„ฑ์œผ๋กœ ์ถ”๊ฐ€๋˜์ง€ ์•Š๋Š”๋‹ค.
    ์™œ๋ƒํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€ ๋ณ€์ˆ˜ ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
    myTimer๋Š” ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์—์„œ let์œผ๋กœ ์ •์˜๋˜์—ˆ๊ณ  ์–ด๋””์—์„œ๋“  ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€ ๋ณ€์ˆ˜(์ƒํƒœ๋‚˜ prop)์ฒ˜๋Ÿผ MyComponent ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ํ‰๊ฐ€๋˜๋„๋ก ํ•˜๋Š” ์š”์†Œ๋Š” ์•„๋‹ˆ๋‹ค.

  • setTimeout์€ โŒ ์ข…์†์„ฑ์œผ๋กœ ์ถ”๊ฐ€๋˜์ง€ ์•Š๋Š”๋‹ค.
    ์™œ๋ƒํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ € ๋‚ด์žฅ API์ด๋ฏ€๋กœ React ๋ฐ ์ปดํฌ๋„ŒํŠธ์™€ ๋…๋ฆฝ์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.


4. CleanUp Fn

๊ฐ€๋” ํด๋ฆฐ์—… ์ž‘์—…์ด ํ•„์š”ํ•œ ์ดํŽ™ํŠธ๋„ ์žˆ๋‹ค.

ํด๋ฆฐ์—… ํŽ‘์…˜ ์‚ฌ์šฉ ์˜ˆ์‹œ

์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ํƒ€์ดํ•‘์„ ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, event.target.value๊ฐ€ ๊ณ„์† ์ž…๋ ฅ๋˜์–ด state๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ณ  ์žˆ๋Š”๋ฐ ์ด๋Š” ํ•„์š” ์ด์ƒ์œผ๋กœ ํŠธ๋ž˜ํ”ฝ์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž๊ฐ€ ํƒ€์ดํ•‘์„ ๋ฉˆ์ถœ ๋•Œ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ ํ›„, ์ž…๋ ฅ์ด ๋๋‚˜๋ฉด ์œ ํšจํ•œ์ง€ ํ™•์ธํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ํŠธ๋ž˜ํ”ฝ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฉ”์ผ/๋น„๋ฐ€๋ฒˆํ˜ธ ํ‚ค๋ฅผ ์ž…๋ ฅ ํ•œ ํ›„, ์˜ˆ๋ฅผ ๋“ค๋ฉด 500๋ฐ€๋ฆฌ์ดˆ ์ด์ƒ ๋ฉˆ์ถ”๋ฉด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์‹คํ–‰ํ•ด๋ณด์ž. ์ด๋Ÿฐ ๊ธฐ์ˆ ์„ ๋””๋ฐ”์šด์‹ฑ์ด๋ผ๊ณ  ํ•œ๋‹ค. ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๋””๋ฐ”์šด์Šค(๊ทธ๋ฃนํ™”)ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ํƒ€์ดํ•‘์„ ์ผ์‹œ ์ค‘์ง€ํ–ˆ์„ ๋•Œ ๋””๋ฐ”์šด์‹ฑํ•˜๋Š” ๊ฒƒ์ธ๋ฐ ์ด๋Š” ๋ธŒ๋ผ์šฐ์ € ๋‚ด์žฅํ•จ์ˆ˜์ธ setTimeout์„ useEffect ๋‚ด๋ถ€์— ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

const Login = (props) => {
  //...
  
  useEffect(() => {
    //500๋ฐ€๋ฆฌ์ดˆ ํ›„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌํ•˜๊ธฐ
    setTimeout(() => {
      console.log("์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ใ…‡ใ…‡");
      setFormIsValid(
        enteredEmail.includes("@") && enteredPassword.trim().length > 6
      );
    }, 500);
  }, [enteredEmail, enteredPassword]);
  
//...

ํ˜„์žฌ ๋ชจ๋“  ํ‚ค ์ž…๋ ฅ์— ๋Œ€ํ•ด 5ms ํ›„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ•˜๊ณ  ์žˆ๋‹ค. ํ‚ค ์ž…๋ ฅ์ด ๋๋‚œ ํ›„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก, ์‚ฌ์šฉ์ž๊ฐ€ ๊ณ„์† ํ‚ค๋ฅผ ์ž…๋ ฅ์ค‘์ธ ๊ฒฝ์šฐ ์ฆ‰, ๋‹ค์Œ ํ‚ค๊ฐ€ ์ž…๋ ฅ๋˜๋ฉด setTimeout์ด ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ์ง€์›Œ์•ผ ํ•œ๋‹ค. ์ฆ‰, ์‚ฌ์šฉ์ž๊ฐ€ ํ‚ค๋ฅผ ๊ณ„์† ์ž…๋ ฅ ์ค‘์ธ ๊ฒฝ์šฐ setTimeout ํƒ€์ด๋จธ๋Š” ๊ณ„์† ์ง€์›Œ์ ธ์•ผ ํ•œ๋‹ค. ์ด๋Ÿด ๋•Œ Clean Up ํŽ‘์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

useEffect()๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์ž์—์„œ return ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ต๋ช…์˜ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ํด๋ฆฐ์—… ํ•จ์ˆ˜๋ผ๊ณ  ํ•œ๋‹ค.

useEffect(() => {
  //500๋ฐ€๋ฆฌ์ดˆ ํ›„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌํ•˜๊ธฐ
  //ํƒ€์ด๋จธ๋ฅผ identifier ์ƒ์ˆ˜์— ํ• ๋‹น
  const identifier = setTimeout(() => {
    console.log("์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ใ…‡ใ…‡");
    setFormIsValid(
      enteredEmail.includes("@") && enteredPassword.trim().length > 6
    );
  }, 500);

  //๐Ÿ”ฅ ํด๋ฆฐ์—… ํŽ‘์…˜ ๋ฐ˜ํ™˜
  return () => {
    console.log("ํด๋ฆฐ์—…");
    //ํƒ€์ด๋จธ ์ง€์šฐ๊ธฐ
    //clearTimeout ๋‚ด์žฅํ•จ์ˆ˜๋กœ identifier ํƒ€์ด๋จธ ์‚ญ์ œ
    clearTimeout(identifier);
  };
}, [enteredEmail, enteredPassword]);
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž๊ฐ€ ํƒ€์ดํ•‘ ์ค‘์ผ ๋•Œ๋Š” ํด๋ฆฐ์—… ํ•จ์ˆ˜๊ฐ€ ์ž‘๋™(ํ‚ค๋ฅผ ์ž…๋ ฅํ•  ๋•Œ ๋งˆ๋‹ค ์ดํŽ™ํŠธ๊ฐ€ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š”๋ฐ, ํด๋ฆฐ์—… ํŽ‘์…˜์ด ๋จผ์ € ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ด๋จธ๊ฐ€ ์‚ญ์ œ๋˜๊ณ  ์‚ญ์ œ๋˜๊ณ  ์‚ญ์ œ๋˜๊ณ )ํ•˜๋ฏ€๋กœ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ง€์—ฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

ํด๋ฆฐ์—… ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š” ์‹œ๊ธฐ

  1. useEffectํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋œ๋‹ค.
    ์ฒ˜์Œ ์‹คํ–‰๋˜๋Š” ๊ฒฝ์šฐ ์ œ์™ธํ•˜๊ณ  ์‹คํ–‰๋  ๋•Œ ๋งˆ๋‹ค ํด๋ฆฐ์—… ํ•จ์ˆ˜๊ฐ€ ๋จผ์ € ์‹คํ–‰๋œ๋‹ค.

  2. ์ดํŽ™ํŠธ๋กœ ํŠน์ •๋œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ DOM์—์„œ ๋งˆ์šดํŠธ ํ•ด์ œ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋œ๋‹ค.
    ์ฆ‰, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ์‚ฌ์šฉ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋œ๋‹ค.

ํด๋ฆฐ์—… ํŽ‘์…˜์€ ๋ชจ๋“  ์ƒˆ๋กœ์šด ์‚ฌ์ด๋“œ์ดํŽ™ํŠธ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์—, ๊ทธ๋ฆฌ๊ณ  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ œ๊ฑฐ๋˜๊ธฐ ์ „์— ์‹คํ–‰๋œ๋‹ค.

  • ์ฒซ ๋ฒˆ์งธ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์—๋Š” ํด๋ฆฐ์—… ํŽ‘์…˜์€ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ํด๋ฆฐ์—… ํŽ‘์…˜์€ ์ƒˆ๋กœ์šด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์‹คํ–‰๋œ๋‹ค.

์ฆ‰, ํด๋ฆฐ์—… ํŽ‘์…˜์ด ์‹คํ–‰๋˜๋Š” ์ˆœ์„œ๋Š”

  • ์ฒ˜์Œ ์•ฑ ์‹คํ–‰์‹œ "์œ ํšจ์„ฑ ๊ฒ€์‚ฌ"
    (์ฒซ ๋ฒˆ์งธ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์‹คํ–‰ ์ „์—๋Š” ํด๋ฆฐ์—… ํŽ‘์…˜ ์‹คํ–‰ X)
  • ํ‚ค ์ž…๋ ฅํ•˜๋ฉด "ํด๋ฆฐ์—…" > "์œ ํšจ์„ฑ ๊ฒ€์‚ฌ"
    (์ƒˆ๋กœ์šด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ํ•จ์ˆ˜ ์‹คํ–‰๋˜๊ธฐ ์ „ ํด๋ฆฐ์—… ํŽ‘์…˜ ์‹คํ–‰ O)
  • ๋˜ ํ‚ค ์ž…๋ ฅํ•˜๋ฉด "ํด๋ฆฐ์—…" > "์œ ํšจ์„ฑ ๊ฒ€์‚ฌ"
    (์ƒˆ๋กœ์šด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ํ•จ์ˆ˜ ์‹คํ–‰๋˜๊ธฐ ์ „ ํด๋ฆฐ์—… ํŽ‘์…˜ ์‹คํ–‰ O)

์ด๋Ÿฐ์‹์œผ๋กœ ์ž‘๋™ํ•œ๋‹ค.

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

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