FrontEnd Develop/Project : Wallet Guardians

๋ณธ๊ฒฉ ์—ฐ๋™ #5. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์˜ ์ดํ•ด๋กœ ๋กœ๊ทธ์ธ ํ›„ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ์ฒ˜๋ฆฌ

Frisbeen 2025. 2. 10. 16:09

๐Ÿ”น 1. ๋ฌธ์ œ ์ƒํ™ฉ ๋ฐ ๊ฐœ์š”

๐Ÿ“Œ ๋ฌธ์ œ: ๋กœ๊ทธ์ธ ํ›„ ์˜ˆ์‚ฐ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์ „์— ํŽ˜์ด์ง€๊ฐ€ ๋จผ์ € ์ด๋™ํ•˜๋Š” ๋ฌธ์ œ

  • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜๋ฉด ๊ธฐ์กด ์˜ˆ์‚ฐ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•œ ํ›„ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•ด์•ผ ํ•จ
  • ํ•˜์ง€๋งŒ ๋น„๋™๊ธฐ ์š”์ฒญ(fetchBudget())์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „์— ํŽ˜์ด์ง€ ์ด๋™ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋จ
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ, ์˜ˆ์‚ฐ์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋„ /goal-setting์œผ๋กœ ์ด๋™ํ•˜๊ฑฐ๋‚˜ ์ž˜๋ชป๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ

๐Ÿ›  ํ•ด๊ฒฐ ๋ชฉํ‘œ

โœ… ๋กœ๊ทธ์ธ ์„ฑ๊ณต ํ›„, ๊ธฐ์กด ์˜ˆ์‚ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„ ํŽ˜์ด์ง€ ์ด๋™
โœ… ๋น„๋™๊ธฐ ์š”์ฒญ(fetchBudget())์ด ๋๋‚  ๋•Œ๊นŒ์ง€ goalAmount ๊ฐ’์„ ๊ธฐ๋‹ค๋ฆฐ ํ›„ ํŽ˜์ด์ง€ ์ „ํ™˜
โœ… UI ๊นœ๋นก์ž„์„ ๋ฐฉ์ง€ํ•˜๊ณ  ์ž์—ฐ์Šค๋Ÿฌ์šด ํ™”๋ฉด ์ „ํ™˜ ์ œ๊ณต


๐Ÿ”น 2. ๋น„๋™๊ธฐ ์š”์ฒญ๊ณผ await์˜ ๊ฐœ๋…

๐Ÿ“Œ ๋น„๋™๊ธฐ ์š”์ฒญ์ด๋ž€?

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

๐Ÿ“Œ await์€ ๋ฌด์—‡์ธ๊ฐ€?

  • await์€ ๋น„๋™๊ธฐ ์š”์ฒญ์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ธฐ๋Šฅ
  • await์„ ์‚ฌ์šฉํ•˜๋ฉด, ํ•ด๋‹น ์š”์ฒญ์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ์ฝ”๋“œ ์‹คํ–‰์„ ๋ฉˆ์ถ”๊ณ  ๊ธฐ๋‹ค๋ฆผ
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ, ์˜ˆ์‚ฐ ๋ฐ์ดํ„ฐ๊ฐ€ ํ™•์‹คํžˆ ๋กœ๋“œ๋œ ํ›„ ํŽ˜์ด์ง€๊ฐ€ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Œ

๐Ÿ”น 3. ๊ธฐ์กด ์ฝ”๋“œ์—์„œ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ  ( ๋น„๋™๊ธฐ ํ•จ์ˆ˜์— await์„ ๋„ฃ์ง€ ์•Š์•˜์Œ)

const handleLogin = async (e) => {
  e.preventDefault();
  setLoading(true);

  try {
    const data = await login(email, password);
    const { accessToken, refreshToken } = data.data;

    localStorage.setItem('accessToken', accessToken);
    localStorage.setItem('refreshToken', refreshToken);

    setFetchingBudget(true);
    const budgetAmount = fetchBudget(); // โŒ ์—ฌ๊ธฐ์—์„œ await์ด ์—†์œผ๋ฉด ๋น„๋™๊ธฐ ์š”์ฒญ์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „์— ๋‹ค์Œ ์ฝ”๋“œ ์‹คํ–‰๋จ
    setFetchingBudget(false);

    // โŒ ๋น„๋™๊ธฐ ์š”์ฒญ์ด ๋๋‚˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ budgetAmount๋ฅผ ํ™•์ธํ•˜์—ฌ ํŽ˜์ด์ง€ ์ด๋™
    if (budgetAmount !== null && budgetAmount > 0) {
      navigate('/main');
    } else {
      navigate('/initial');
    }
  } catch (error) {
    console.error('๋กœ๊ทธ์ธ ์‹คํŒจ:', error);
  } finally {
    setLoading(false);
  }
};

โš ๏ธ ๋ฌธ์ œ์   -> ์˜ˆ์‚ฐ์„ ๊ฐ€์ง€๊ณ ์˜ค๊ธฐ๋„ ์ „์— ๋ฐ”๋กœ navigate๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†ํ›„ํ•จ.. ใ… 

  1. fetchBudget()์ด ์‹คํ–‰๋˜์—ˆ์ง€๋งŒ, ์™„๋ฃŒ๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ budgetAmount ๊ฐ’์„ ํ™•์ธํ•˜๋ ค๊ณ  ํ•จ
  2. ๋น„๋™๊ธฐ ์š”์ฒญ์ด ๋๋‚˜๊ธฐ ์ „์— navigate()๊ฐ€ ์‹คํ–‰๋˜์–ด ์ž˜๋ชป๋œ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Œ
  3. ๊ฒฐ๊ณผ: ๊ธฐ์กด ์˜ˆ์‚ฐ์ด ์žˆ๋Š” ์‚ฌ์šฉ์ž๋„ /goal-setting์œผ๋กœ ์ด๋™ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

๐Ÿ”น 4. ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: await์„ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์š”์ฒญ์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ

const handleLogin = async (e) => {
  e.preventDefault();
  setLoading(true);

  try {
    const data = await login(email, password);
    const { accessToken, refreshToken } = data.data;

    localStorage.setItem('accessToken', accessToken);
    localStorage.setItem('refreshToken', refreshToken);

    setModalMessage({
      type: 'success',
      message: '๋กœ๊ทธ์ธ ์„ฑ๊ณต! ์˜ˆ์‚ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค!',
    });

    // โœ… fetchBudget()์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ
    setFetchingBudget(true);
    const budgetAmount = await fetchBudget();
    setFetchingBudget(false);

    console.log('๐Ÿฆ ๋กœ๊ทธ์ธ ํ›„ ๋ฐ›์€ ์˜ˆ์‚ฐ ๊ธˆ์•ก:', budgetAmount);

    // โœ… ๋น„๋™๊ธฐ ์š”์ฒญ์ด ๋๋‚œ ํ›„ ํŽ˜์ด์ง€ ์ด๋™ (500ms ๋Œ€๊ธฐ → UI ๊นœ๋นก์ž„ ๋ฐฉ์ง€)
    setTimeout(() => {
      navigate(budgetAmount !== null && budgetAmount > 0 ? '/main' : '/initial');
    }, 500);
  } catch (error) {
    console.error('๋กœ๊ทธ์ธ ์‹คํŒจ:', error);
    setModalMessage({
      type: 'error',
      message: '๋กœ๊ทธ์ธ ์‹คํŒจ! ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.',
    });
  } finally {
    setLoading(false);
  }
};

๐Ÿ”น 5. await์ด ์ ์šฉ๋œ ํ›„ ๋น„๋™๊ธฐ ํŠน์„ฑ์„ ๊ณ ๋ คํ•œ ํ๋ฆ„

๐Ÿ“Œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญ → ๋กœ๊ทธ์ธ ์š”์ฒญ → ๋กœ๊ทธ์ธ ์„ฑ๊ณต → fetchBudget() ์‹คํ–‰ → ๋ฐ์ดํ„ฐ๊ฐ€ ๋กœ๋“œ๋  ๋•Œ๊นŒ์ง€ await์œผ๋กœ ๋Œ€๊ธฐ → budgetAmount ํ™•์ธ → ํŽ˜์ด์ง€ ์ด๋™

 

1๏ธโƒฃ handleLogin() ์‹คํ–‰ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์‹คํ–‰
2๏ธโƒฃ await login(email, password) ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ
3๏ธโƒฃ ํ† ํฐ ์ €์žฅ accessToken, refreshToken์„ localStorage์— ์ €์žฅ
4๏ธโƒฃ await fetchBudget() ์„œ๋ฒ„์—์„œ ์˜ˆ์‚ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ
5๏ธโƒฃ budgetAmount ํ™•์ธ ์˜ˆ์‚ฐ์ด ์žˆ์œผ๋ฉด /main์œผ๋กœ ์ด๋™, ์—†์œผ๋ฉด /initial์œผ๋กœ ์ด๋™
6๏ธโƒฃ setTimeout() UI ๊นœ๋นก์ž„ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด 500ms ๋Œ€๊ธฐ ํ›„ ํŽ˜์ด์ง€ ์ด๋™

๐Ÿš€ ์ตœ์ข… ์ •๋ฆฌ

โœ”๏ธ ๋น„๋™๊ธฐ ์š”์ฒญ(fetchBudget())์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ await์„ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ€๊ธฐ
โœ”๏ธ ๊ธฐ์กด ์˜ˆ์‚ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์™„์ „ํžˆ ๊ฐ€์ ธ์˜จ ํ›„ ํŽ˜์ด์ง€ ์ด๋™
โœ”๏ธ UI ๊นœ๋นก์ž„์„ ๋ฐฉ์ง€ํ•˜๊ณ  ์ž์—ฐ์Šค๋Ÿฌ์šด ํ™”๋ฉด ์ „ํ™˜์„ ์ œ๊ณต (setTimeout(500ms))


๐ŸŽฏ ์ตœ์ข… ๊ฒฐ๋ก 

๐Ÿ”ฅ await fetchBudget()์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ ํ›„ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•จ์œผ๋กœ์จ
โœ”๏ธ ์ž˜๋ชป๋œ ํŽ˜์ด์ง€ ์ด๋™ ๋ฐฉ์ง€
โœ”๏ธ UI ๊นœ๋นก์ž„ ๋ฐฉ์ง€
โœ”๏ธ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜(UX) ๊ฐœ์„ 

์ด์ œ ๋กœ๊ทธ์ธ ํ›„ ๊ธฐ์กด ์˜ˆ์‚ฐ์ด ์žˆ๋Š” ์‚ฌ์šฉ์ž๋Š” ๋ฐ”๋กœ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ณ ,
์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋Š” ์˜ˆ์‚ฐ์„ ์„ค์ •ํ•˜๋„๋ก ์•ˆ๋‚ดํ•˜๋Š” /goal-setting ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ๐Ÿš€๐Ÿ”ฅ