โœ๏ธ What I Learned/TIL

[TIL] ํด๋ฆฐ ์ฝ”๋“œ - Custom Hook, Container - Presentational ํŒจํ„ด, ํŒŒ์ผ/ํด๋” ๊ตฌ์กฐ(ํŒจํ„ด)

Jiwon() 2023. 7. 5. 00:34

1. ๐Ÿ’ซ Custom Hook

1) ๋„ˆ๋ฌด๋‚˜๋„ ๊ถ๊ธˆํ–ˆ๋˜ ๋‚ด์šฉ ๋“œ๋””์–ด!

์ €๋ฒˆ ๋‰ด์Šคํ”ผ๋“œ ํ”„๋กœ์ ํŠธ ํ•  ๋•Œ ๊ณ„์†ํ•ด์„œ input๊ฐ’์„ ํ•ธ๋“ค๋งํ•˜๋Š” hook๋“ค์„ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์ด๊ฑธ ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ๋” ํด๋ฆฐํ•˜๊ฒŒ ๋ฆฌํŒฉํ† ๋ง ํ•  ์ˆ˜ ์žˆ์„์ง€ ๊ณ ๋ฏผ์„ ํ–ˆ์—ˆ๋‹ค.

 

2) ์‚ฌ์šฉ๋ฐฉ๋ฒ•

  1. hooks ํด๋” ์ƒ์„ฑ ํ›„ use~๋กœ ์‹œ์ž‘ํ•˜๋Š” (ex. useHookName.js) ํŒŒ์ผ ์ƒ์„ฑ
  2. useState, useEffect, useRef ๋“ฑ ๊ธฐ์กด ๋ฆฌ์•กํŠธ ํ›…์„ ์ด์šฉํ•ด์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง์„ custom hook์œผ๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค.
    โžก๏ธ ์ด ๋•Œ, custom hook์—๋Š” state์™€ handler ๋‘ ๊ฐ€์ง€๋ฅผ ์ •์˜ํ•ด์ค€๋‹ค.
  3. export default ํ•ด์ค€ ๋’ค ํ•„์š”ํ•œ ๊ณณ์—์„œ importํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉด ๋!

 

// useInput.js (์˜ˆ์‹œ)
import { useState } from "react";

const useInput = () => {

  // state
  const [value, setValue] = useState('');

  // handler
  const handler = (e) => {
    setValue(e.target.value)
  }

  return [value, handler];
 };

export default useInput;

 

// import React, { useState } from "react";
import useInput from "../hooks/useInput";
import SignUp from "./SignUp";

const App = () => {

  // 1. custom hook ์‚ฌ์šฉ
  const [name, onChangeNameHandler] = useInput();
  const [password, onChangePasswordHandler] = useInput();

  // 2. ์ด์ œ๊นŒ์ง€ ํ•ด์™”๋˜ ๊ธฐ์กด ๋ฐฉ์‹
  // const [name, setName] = useState('');
  // const [password, setPassword] = useState('');
  // const onChangeNameHandler = (e) => {
  //   setName(e.target.value);
  //  }
  // const onChangePasswordHandler = (e) => {
  //   setPassword(e.target.value);
  // }


  return (
    <>
      <h1>Custom Hooks</h1>
      <input type="text" value={name} onChange={onChangeNameHandler} />
      <input type="password" value={password} onChange={onChangePasswordHandler}/>
      <div>
        <SignUp />
      </div>
    </>
  );
};

export default App;

 

 

3) ์žฅ์ 

  • ์ฝ”๋“œ์˜ ๋ฐ˜๋ณต ์‚ฌ์šฉ์„ ์ค„์—ฌ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์ง
  • ๊ฐ€๋…์„ฑ, ์œ ์ง€๋ณด์ˆ˜์„ฑ ์ฐจ์›์—์„œ๋„ good!

 


2. ๐Ÿชœ Container - Presentational ํŒจํ„ด

์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‘ ๊ฐœ์˜ ๊ณ„์ธต์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ํŒจํ„ด

  • JavaScript(๊ธฐ๋Šฅ)๊ณผ JSX(UI)๋กœ ๋‚˜๋ˆ„๋Š” ๋ฐฉ๋ฒ•

๋ญ์•ผ ๊ทธ๋ƒฅ ํ”ํ•œ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ์ž–์•„?

 

  • Container : JavaScript ์˜์—ญ, UI๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ๋ณ€ํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ ๋กœ์ง์— ์ง‘์ค‘ํ•˜๋Š” ๊ณ„์ธต
  • Presentational : JSX ์˜์—ญ, ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์ด๋Š” UI๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑ๋˜์–ด์•ผ ํ•˜๋Š”์ง€์—๋งŒ ์ง‘์ค‘ํ•˜๋Š” ๊ณ„์ธต
  • Presentational์„ Container๋กœ ๊ฐ์‹ผ ํ›„์— ํ•„์š”ํ•œ ์ •๋ณด์™€ ๋กœ์ง๋“ค์„ props๋กœ ์ „๋‹ฌํ•ด์ฃผ๋Š” ํ˜•ํƒœ

 

React 16.8 ์ดํ›„ Hook์˜ ๋“ฑ์žฅ์œผ๋กœ, ์ž˜ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š๋Š” ํŒจํ„ด์ด๋ผ๊ณ  ํ•จ

 

 

 


3. ๐Ÿ—‚๏ธ ํŒŒ์ผ/ํด๋” ๊ตฌ์กฐ(ํŒจํ„ด)

Custom hook์€ useState, useEffect ๋“ฑ ๋ฆฌ์•กํŠธ ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋“ค์„ ์ปค์Šคํ…€ ํ›…์œผ๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค๋Š” ๊ฒƒ์€ ์ดํ•ดํ–ˆ์Œ.

์ „๋ถ€ํ„ฐ ๊ถ๊ธˆํ–ˆ๋˜ ๊ฑด, '๋‚ ์งœ ํ˜•์‹ ๋ณ€ํ™˜'์ด๋‚˜ '๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ' ๊ฐ™์€ ๊ธฐ๋Šฅ๋“ค์€ ์™ ๋งŒํ•œ ์›น์„œ๋น„์Šค์—์„œ ํ”ํ•˜๊ฒŒ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง์ธ๋ฐ ์ด๋Ÿฐ ๊ฑด ์–ด๋–ป๊ฒŒ ํ•ธ๋“ค๋งํ• ๊นŒ?

 

1) ํ•จ์ˆ˜ ๋ชจ๋“ˆ๋กœ ๊ด€๋ฆฌ

์˜ˆ์‹œ - timestamp๋ฅผ 2023. 7. 5 12:07 ํ˜•ํƒœ๋กœ ์“ฐ๊ณ  ์‹ถ์œผ๋ฉด?
formatTime.js๋ผ๋Š” ์Šค๋‹ˆํŽซ ๋ชจ๋“ˆ jsํŒŒ์ผ ์ƒ์„ฑ ํ›„, ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์— importํ•ด์„œ ๊ฐ–๋‹ค ์“ฐ๊ธฐ

 

// formatTime.js
const formatTime = (timestamp) => {
  const date = new Date(timestamp);
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const hour = date.getHours().toString().padStart(2, '0');
  const minute = date.getMinutes().toString().padStart(2, '0');

  return `${year}. ${month}. ${day} ${hour}:${minute}`
};

export default formatTime;

 

// ContentsList.jsx
import React from 'react';
import formatTime from './formatTime';

const ContentsList = () => {

  // ...

  return (
    <>
      ...
      {*/ ์—ฌ๊ธฐ์„œ todo.createdAt์€ timestamp ํ˜•์‹/*}
      "๊ธ€ ์“ด ์‹œ๊ฐ„" : {formatTime(todo.createdAt)}
    </>
  );
}

export default ContentsList;

 

 

2) ํŒŒ์ผ/ํด๋” ๋ถ„๋ฅ˜ ๊ตฌ์กฐ, ํด๋”๋ช… ์ปจ๋ฒค์…˜

๐Ÿ“ฆsrc
 โ”ฃ ๐Ÿ“‚hooks
 โ”ƒ โ”— ๐Ÿ“œuseInput.js
 โ”ฃ ๐Ÿ“‚lib
 โ”ƒ โ”ฃ ๐Ÿ“‚helpers
 โ”ƒ โ”ƒ โ”— ๐Ÿ“œpasswordValidation.js
 โ”ƒ โ”ƒ โ”— ๐Ÿ“œformatTime.js
 โ”ƒ โ”ฃ ๐Ÿ“‚services
 โ”ƒ โ”— ๐Ÿ“‚utils
 โ”ฃ ๐Ÿ“œApp.jsx
 โ”— ๐Ÿ“œindex.js

lib, utils, helpers, services

  • lib : ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜๋‚˜ ๊ณตํ†ต ๋กœ์ง์„ ๋ณด๊ด€ํ•˜๋Š” ํด๋”๋กœ, ์ผ๋ฐ˜์ ์œผ๋กœ ํ”„๋กœ์ ํŠธ ์ „์ฒด์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ฝ”๋“œ๋ฅผ ๋ชจ์•„๋‘๋Š” ๊ณณ
  • utils / helpers : ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ ํ•จ์ˆ˜, ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜, ํ—ฌํผ ํ•จ์ˆ˜
  • services : API ํ˜ธ์ถœ์ด๋‚˜ DB ์—ฐ๊ฒฐ ๋“ฑ ์„œ๋น„์Šค ๊ด€๋ จ

 

์œ ํ‹ธ ํ•จ์ˆ˜์™€ ํ—ฌํผ ํ•จ์ˆ˜

๋‘˜์€ ๋น„์Šทํ•œ ๊ฐœ๋…์ธ ๊ฒƒ ๊ฐ™์œผ๋‚˜ ์ฐพ์•„๋ณธ ์ฐจ์ด์ ์œผ๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Œ (์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ์ธ๊ฐ€ ์˜์–ด ์‚ฌ์ดํŠธ ๋ฒˆ์—ญํ•œ๊ฑฐ๋ผ ์•ฝ๊ฐ„ ์–ด์ƒ‰)

  • utils : ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์€ ์Šค๋‹ˆํŽซ์„ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ณณ. utils์—์„œ์˜ ์ž‘์€ ๋ชจ๋“ˆ๋กœ ๋” ํฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Œ
  • helpers: ์ฝ”๋“œ ์•„ํ‚คํ…์ฒ˜ ์Šค๋‹ˆํŽซ์„ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„์— ๊ฐ€๊น๋‹ค๊ณ  ๋ณด๋ฉด ๋จ. ์ปดํฌ๋„ŒํŠธ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ๊ณผ ๊ฐœ๋ฐœ์ž ์ธ์ฒด๊ณตํ•™(=๊ฐœ๋ฐœ์ž๋“ค์ด ํ‰์†Œ์— ํ•„์š”๋กœ ํ•˜๋Š” ๊ธฐ๋Šฅ๊ณผ ๋””์ž์ธ์— ๋Œ€ํ•œ ๊ฒƒ๋“ค)์— ํ•„์ˆ˜์ ์ธ ๊ฒƒ๋“ค
  Utils Helpers
๋ชฉ์  ํ”„๋กœ๊ทธ๋žจ์˜ ํŠน์ • ๋ถ€๋ถ„์— ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์€ ์ผ๋ฐ˜ ๋˜๋Š” ์ผ๋ฐ˜ ์ž‘์—… ์ˆ˜ํ–‰ ํ”„๋กœ๊ทธ๋žจ์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„์— ๋Œ€ํ•œ ์ง€์› ๋˜๋Š” ์›์กฐ ์ œ๊ณต
๋ฒ”์œ„ ํ”„๋กœ๊ทธ๋žจ ์ „์ฒด ๋˜๋Š” ์—ฌ๋Ÿฌ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์ผ๋ฐ˜์ ์œผ๋กœ ํŠน์ • ๋ชจ๋“ˆ ๋˜๋Š” ํ”„๋กœ๊ทธ๋žจ์˜ ์ผ๋ถ€ ๋‚ด์—์„œ ์‚ฌ์šฉ
์˜์กด์„ฑ ์ผ๋ฐ˜์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„๊ณผ ๋…๋ฆฝ์  ํ”„๋กœ๊ทธ๋žจ์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„์ด๋‚˜ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ
์˜ˆ์‹œ ๋ฌธ์ž์—ด ์กฐ์ž‘ ํ•จ์ˆ˜, ์ˆ˜ํ•™ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ Form ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ•จ์ˆ˜, ๋ฐ์ดํ„ฐ ํฌ๋งทํŒ… ๋“ฑ