๐Ÿ“– TIL - ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๊ธฐ์ดˆ์™€ React์—์„œ์˜ ํ™œ์šฉ

์Š˜ยท2025๋…„ 3์›” 6์ผ

๐Ÿ“– TIL

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

๋Š˜ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ React์—์„œ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊นŒ์ง€ ๊ณต๋ถ€ํ–ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋งŒ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ๋„˜์–ด์˜ค๋‹ˆ ์ƒˆ๋กœ์šด ๊ฐœ๋…๋“ค์ด ๋งŽ์•˜๊ณ , ํŠนํžˆ ํƒ€์ž… ์‹œ์Šคํ…œ๊ณผ ์ œ๋„ค๋ฆญ, ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž… ๋“ฑ์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ํ•„์š”ํ–ˆ๋‹ค...

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์ฐจ๊ทผ์ฐจ๊ทผ ์ ‘๊ทผํ–ˆ๋‹ค. ์ •์  ํƒ€์ž… ์‹œ์Šคํ…œ์ด๋ž€ ๋ฌด์—‡์ธ์ง€, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ธ์ง€, ๊ทธ๋ฆฌ๊ณ  ๋‹ค์–‘ํ•œ ํƒ€์ž… ์„ ์–ธ ๋ฐฉ๋ฒ•๊ณผ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์„ ํ•™์Šตํ–ˆ๋‹ค. ์‹ค์ œ React ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด๋ณด๋ฉฐ ์‹ค๋ฌด์—์„œ ์–ด๋–ป๊ฒŒ ํ™œ์šฉ๋˜๋Š”์ง€ ํŒŒ์•…ํ•˜๋Š” ๋ฐ ์ค‘์ ์„ ๋‘์—ˆ๋‹ค.

๐Ÿ“š ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ž€?

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์— ํƒ€์ž… ์‹œ์Šคํ…œ์„ ์ถ”๊ฐ€ํ•œ ์–ธ์–ด๋ผ๊ณ  ํ•œ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‹ฌ๋ฆฌ๋Š” ์ค‘์— ์˜ค๋ฅ˜๋ฅผ ๋ฐœ๊ฒฌํ•˜๋Š” "๋™์  ํƒ€์ž… ์–ธ์–ด"๋ผ๋ฉด, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ฝ”๋“œ ์ž‘์„ฑ ๋‹จ๊ณ„์—์„œ ์˜ค๋ฅ˜๋ฅผ ์žก์•„๋‚ด๋Š” "์ •์  ํƒ€์ž… ์–ธ์–ด"๋‹ค.

์š”๋ฆฌ ๋ ˆ์‹œํ”ผ๋กœ ๋น„์œ ํ•˜๋ฉด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์žฌ๋ฃŒ์™€ ์–‘์„ ๋Œ€์ถฉ ๋„ฃ๊ณ  ๋ง›์„ ๋ณด๋ฉด์„œ ์š”๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด๊ณ , ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ •ํ™•ํ•œ ์žฌ๋ฃŒ์™€ ์–‘์„ ๋ฏธ๋ฆฌ ์ ์–ด๋‘๊ณ  ๊ทธ๋Œ€๋กœ ๋”ฐ๋ผํ•˜๋Š” ๋ฐฉ์‹์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์‹ค์ˆ˜ํ•  ํ™•๋ฅ ์ด ํ™•์‹คํžˆ ์ค„์–ด๋“ ๋‹ค.

๐Ÿ”ค ํƒ€์ž… ์„ ์–ธํ•˜๊ธฐ

ํƒ€์ž… ์„ ์–ธ์€ ์ƒ๊ฐ๋ณด๋‹ค ๊ฐ„๋‹จํ–ˆ๋‹ค. ๋ณ€์ˆ˜๋‚˜ ํ•จ์ˆ˜ ์˜†์— : ํƒ€์ž…์„ ๋ถ™์ด๋ฉด ๋œ๋‹ค.

// ๊ธฐ๋ณธ ํƒ€์ž…๋“ค
let name: string = '์ฝ”์ฝ”';
let age: number = 11;
let isSmart: boolean = true;
let hobbies: string[] = ['๋†€๊ธฐ', '์ž๊ธฐ'];

// ๊ฐ์ฒด ํƒ€์ž…
let user: { name: string; age: number } = { name: '์ฝ”์ฝ”', age: 11 };

// ํ•จ์ˆ˜ ํƒ€์ž…
function greet(name: string): string {
  return `์•ˆ๋…•, ${name}!`;
}

๐Ÿ”„ type vs interface

ํƒ€์ž…๊ณผ ์ธํ„ฐํŽ˜์ด์Šค ๋‘˜ ๋‹ค ํƒ€์ž…์„ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ๋ฐ, ๋ฏธ๋ฌ˜ํ•œ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

// type์œผ๋กœ ์ •์˜
type User = {
  name: string;
  age: number;
};

// interface๋กœ ์ •์˜
interface Person {
  name: string;
  age: number;
}

๋‘˜์ด ์–ผํ• ๋น„์Šทํ•ด ๋ณด์ด์ง€๋งŒ ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋‹ˆ ์ฐจ์ด์ ์ด ์žˆ์—ˆ๋‹ค:

  1. ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋‹ค:
interface Person {
  name: string;
}

interface Person {
  age: number;
} // ์ด๋Ÿฌ๋ฉด Person์€ name๊ณผ age ๋‘˜ ๋‹ค ๊ฐ€์ง„ ํƒ€์ž…์ด ๋œ๋‹ค
  1. ํƒ€์ž…์€ ์œ ๋‹ˆ์˜จ, ์ธํ„ฐ์„น์…˜ ๋“ฑ ๋” ๋‹ค์–‘ํ•œ ํ‘œํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค:
type ID = string | number;
type Employee = Person & { employeeId: string };

๋‘˜ ์ค‘ ์–ด๋А ๊ฒƒ์„ ์จ์•ผ ํ• ์ง€ ๊ณ ๋ฏผํ–ˆ๋Š”๋ฐ, ๋ฌธ์„œ์—์„œ๋Š” "๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋‘˜ ๋‹ค ์“ธ ์ˆ˜ ์žˆ๊ณ , ํ™•์žฅ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ, ๋ณต์žกํ•œ ํƒ€์ž… ํ‘œํ˜„์ด ํ•„์š”ํ•˜๋ฉด ํƒ€์ž…์„ ์“ฐ๋ผ"๊ณ  ํ–ˆ๋‹ค. ์ผ๋‹จ์€ ํƒ€์ž…๋ถ€ํ„ฐ ์ต์ˆ™ํ•ด์ง€๋Š” ๊ฑธ๋กœ...

๐Ÿงฌ ์ œ๋„ค๋ฆญ(Generic) - ํƒ€์ž…์˜ ๋ณ€์ˆ˜ํ™”

์ œ๋„ค๋ฆญ์ด๋ž€ ๊ฐœ๋…์ด ์ฒ˜์Œ์—๋Š” ์ข€ ์–ด๋ ค์› ๋‹ค. ํƒ€์ž…์„ ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฑด๋ฐ...

function getFirstItem<T>(items: T[]): T | undefined {
  return items[0];
}

const numberItem = getFirstItem([1, 2, 3]); // numberItem: number
const stringItem = getFirstItem(['a', 'b', 'c']); // stringItem: string

์ด๋Ÿฐ ์‹์œผ๋กœ T ์ž๋ฆฌ์— ์‹ค์ œ ์‚ฌ์šฉํ•  ํƒ€์ž…์ด ๋“ค์–ด๊ฐ„๋‹ค. React์˜ useState์—์„œ๋„ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋‚˜์˜ด:

const [users, setUsers] = useState<User[]>([]);

์ฒ˜์Œ์—๋Š” ""๊ฐ€ ๋ญ์ง€? ์‹ถ์—ˆ๋Š”๋ฐ, "์–ด๋–ค ํƒ€์ž…์ด๋“  ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋Š” ์ž๋ฆฌ"๋ผ๊ณ  ์ƒ๊ฐํ•˜๋‹ˆ ์ข€ ์ดํ•ด๊ฐ€ ๋๋‹ค.

๐Ÿ› ๏ธ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—๋Š” ๊ธฐ์กด ํƒ€์ž…์„ ๋ณ€ํ˜•ํ•ด์„œ ์ƒˆ ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…์ด๋ผ๋Š” ๊ฒƒ๋„ ์žˆ๋‹ค. ์ด ๋ถ€๋ถ„์ด ํŠนํžˆ ์œ ์šฉํ–ˆ๋‹ค.

type Todo = {
  id: string;
  title: string;
  completed: boolean;
};

// id์™€ completed๋งŒ ์„ ํƒ
type ToggleTodo = Pick<Todo, 'id' | 'completed'>;

// title์„ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ์†์„ฑ
type TodoWithoutTitle = Omit<Todo, 'title'>;

// ๋ชจ๋“  ์†์„ฑ์„ ์„ ํƒ์ ์œผ๋กœ
type PartialTodo = Partial<Todo>;

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ธฐ์กด ํƒ€์ž…์—์„œ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ์ผ๋ถ€๋ฅผ ์ œ์™ธํ•œ ์ƒˆ ํƒ€์ž…์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์„œ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์•„์ง„๋‹ค.

โš›๏ธ React์—์„œ ์ ์šฉํ•ด๋ณด๊ธฐ

์˜ค๋Š˜ ๋ฐฐ์šด ๊ฑธ ํ† ๋Œ€๋กœ ๊ฐ„๋‹จํ•œ Todo ์•ฑ์„ ๋งŒ๋“ค์–ด๋ดค๋‹ค.

type Todo = {
  id: string;
  title: string;
  completed: boolean;
};

type ToggleTodo = Omit<Todo, 'title'>;

function TodoItem({
  id,
  title,
  completed,
  onDeleteClick,
  onToggleClick,
}: Todo & {
  onDeleteClick: (id: string) => void;
  onToggleClick: (todo: ToggleTodo) => void;
}) {
  return (
    <div>
      <span
        onClick={() => onToggleClick({ id, completed })}
        style={{ textDecoration: completed ? 'line-through' : 'none' }}
      >
        {title}
      </span>
      <button onClick={() => onDeleteClick(id)}>์‚ญ์ œ</button>
    </div>
  );
}

React์™€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฐ™์ด ์“ฐ๋‹ˆ props์˜ ํƒ€์ž…์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์–ด์„œ ์ข‹์•˜๋‹ค. ํŠนํžˆ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…์„ ์ง€์ •ํ•˜๋‹ˆ ์‹ค์ˆ˜๋กœ ์ž˜๋ชป๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์ผ์ด ์—†์–ด์กŒ๋‹ค.

๐Ÿ’ก ๋ฐฐ์šด ์  & ๋А๋‚€ ์ 

  1. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ฒ˜์Œ์—๋Š” ๋ฒˆ๊ฑฐ๋กญ์ง€๋งŒ ์ฝ”๋“œ ์•ˆ์ •์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ํฌ๊ฒŒ ๋†’์—ฌ์ค€๋‹ค.
  2. ํƒ€์ž…์ด ๋ช…ํ™•ํ•˜๋‹ˆ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ๋„ ์‰ฌ์›Œ์กŒ๋‹ค.
  3. type๊ณผ interface ์ค‘ ์–ด๋–ค ๊ฑธ ์จ์•ผ ํ• ์ง€๋Š” ์•„์ง ์ข€ ๋” ๊ณ ๋ฏผํ•ด๋ด์•ผ๊ฒ ๋‹ค.

์•„์ง ์ดˆ๋ณด์ง€๋งŒ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์™œ ์š”์ฆ˜ ํ•„์ˆ˜ ๊ธฐ์ˆ ์ด ๋๋Š”์ง€ ์กฐ๊ธˆ์”ฉ ์ดํ•ด๊ฐ€ ๊ฐ„๋‹ค. ๋‚ด์ผ์€ React์˜ ๊ฝƒ์ธ Next๋ฅผ ๊ณต๋ถ€ํ•ด๋ด์•ผ๊ฒ ๋‹ค...!!

profile
์ฃผ๋‹ˆ์–ด ํ”„๋ก ํŠธ์—”๋“œ ์„ฑ์žฅ๊ธฐ ๊ธฐ๋ก๊ธฐ๋ก

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