JiSoo's Devlog

[์šฐ์•„ํ•œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ] 8์žฅ ๋ณธ๋ฌธ

Frontend/Typescript

[์šฐ์•„ํ•œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ] 8์žฅ

์ง€์ˆญ์ˆญ์ˆญ 2025. 6. 6. 00:02

๐Ÿ“ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ํƒ€์ž…

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…

interface Component<P = {}, S = {}, SS = any> extends ComponentLifecycle<P, S, SS> {}

class Component<P, S> {
  /* ~~ */
}

class PureComponent<P = {}, SS = any> extends Component<P, S, SS> {}

React.Component์™€ React.PureComponent์˜ ํƒ€์ž… ์ •์˜๋Š” ์œ„ ์ฝ”๋“œ์™€ ๊ฐ™๊ณ  P์™€ S๋Š” ๊ฐ๊ฐ props์™€ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค..

์ƒํƒœ๊ฐ€ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ์ผ ๋•Œ๋Š” ์ œ๋„ค๋ฆญ์˜ ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ํƒ€์ž…์„ ๋„˜๊ฒจ์ฃผ๋ฉด ์ƒํƒœ์— ๋Œ€ํ•œ ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…

ํ•จ์ˆ˜ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ด ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ์„ ์–ธํ•  ๋•Œ ๊ฐ€์žฅ ๋งŽ์ด ๋ณผ ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋Š” React.FC๋‚˜ React.VFC๋กœ ํƒ€์ž…์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

FC๋Š” FunctionComponent์˜ ์•ฝ์ž๋กœ React.FC์™€ React.VFC๋Š” ๋ฆฌ์•กํŠธ์—์„œ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์˜ ํƒ€์ž… ์ง€์ •์„ ์œ„ํ•ด ์ œ๊ณต๋˜๋Š” ํƒ€์ž…์ด๋‹ค.

React.FC๋Š” ์•”๋ฌต์ ์œผ๋กœ children์„ ํฌํ•จํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์—์„œ children์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ children props๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค. ๋”ฐ๋ผ์„œ children props๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ๋” ์ •ํ™•ํ•œ ํƒ€์ž… ์ง€์ •์„ ์œ„ํ•ด React.VFC๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ๋ฆฌ์•กํŠธ v18๋กœ ๋„˜์–ด์˜ค๋ฉด์„œ React.VFC๊ฐ€ ์‚ญ์ œ๋˜๊ณ  React.FC์—์„œ children์ด ์‚ฌ๋ผ์ ธ์„œ React.FC๋‚˜ props ํƒ€์ž…, ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์ง์ ‘ ์ง€์ •ํ•˜๋Š” ํ˜•ํƒœ๋กœ ํƒ€์ดํ•‘ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

Children props ํƒ€์ž… ์ง€์ •

type PropsWithChildren<P> = P & { children?๏ผš ReactNode | undefined };

๋ณดํŽธ์ ์ธ children ํƒ€์ž…์€ ReactNode | undefined ๊ฐ€ ๋œ๋‹ค.

ReactNode๋Š” ReactElement ์™ธ์—๋„ ์—ฌ๋Ÿฌ ํƒ€์ž…์„ ํฌํ•จํ•˜๋Š” ํƒ€์ž…์œผ๋กœ ๊ตฌ์ฒด์ ์œผ๋กœ ํƒ€์ดํ•‘ํ•˜๋Š” ์šฉ๋„์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.

ํŠน์ • ๋ฌธ์ž์—ด๋งŒ ํ—ˆ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋Š” children์— ๋Œ€ํ•ด ์ถ”๊ฐ€๋กœ ํƒ€์ดํ•‘ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

children์— ๋Œ€ํ•œ ํƒ€์ž… ์ง€์ •์€ ๋‹ค๋ฅธ prop ํƒ€์ž… ์ง€์ •๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

render ๋ฉ”์„œ๋“œ์™€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฐ˜ํ™˜ ํƒ€์ž… - React.ReactElement vs JSX.Element vs React.ReactNode

interface ReactElement<P = any,
  T extends string | JSXElementConstructor<any> =
  | string
  | JSXElementConstructor<any>
> {
  type: T;
  props: P;
  key: Key | null;
}

 

๋ฆฌ์•กํŠธ๋Š” ์‹ค์ œ DOM์ด ์•„๋‹ˆ๋ผ ๊ฐ€์ƒ์˜ DOM์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ Œ๋”๋งํ•˜๋Š”๋ฐ ๊ฐ€์ƒ DOM์˜ ์—˜๋ฆฌ๋จผํŠธ๋Š” ReactElement ํ˜•ํƒœ๋กœ ์ €์žฅ๋œ๋‹ค.

ReactElement ํƒ€์ž…์€ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํฌ๋งท

 

JSX.Element ํƒ€์ž…์€ ์•ž์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋‹ค์‹œํ”ผ ๋ฆฌ์•กํŠธ์˜ ReactElement๋ฅผ ํ™•์žฅํ•˜๊ณ  ์žˆ๋Š” ํƒ€์ž…์ด๋ฉฐ

๊ธ€๋กœ๋ฒŒ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์ •์˜๋˜์–ด ์žˆ์–ด ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…์„ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.

 

๐Ÿ‘‰๐Ÿป ๊ธ€๋กœ๋ฒŒ ๋„ค์ž„์ŠคํŽ˜์ด์Šค

ํ”„๋กœ๊ธ€๋ž˜๋ฐ์—์„œ ์‹๋ณ„์ž๊ฐ€ ์ •์˜๋˜๋Š” ์ „์—ญ์ ์ธ ๋ฒ”์œ„

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋‚˜ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ „์—ญ ์Šค์ฝ”ํ”„์—์„œ ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋‚˜ ํ•จ์ˆ˜ ๋“ฑ์€ ๊ธ€๋กœ๋ฒŒ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์†ํ•œ๋‹ค.

 

type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
type ReactFragment = {} | Iterable<ReactNode>;

type ReactNode =
  | ReactChild
  | ReactFragment
  | ReactPortal
  | boolean
  | null
  | undefined;

 

ReactElement, ReactNdoe, JSX.Element ํ™œ์šฉํ•˜๊ธฐ

3๊ฐœ ์ „๋ถ€ ๋ฆฌ์•กํŠธ์˜ ์š”์†Œ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํƒ€์ž…

 

ReactElement

JSX๊ฐ€ createElement ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ๋ฒ•

JSX๋Š” ๋ฆฌ์•กํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ๋ฒ•์ด๋ฉฐ ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ๋Š” JSX ๋ฌธ๋ฒ•์„ createElement ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋ฌธ์œผ๋กœ ๋ณ€ํ™˜ํ•ด ๋ฆฌ์•กํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

 

ReactNode

ReactChild ํƒ€์ž…์€ ReactElement ๋ณด๋‹ค๋Š” ์ข€ ๋” ๋„“์€ ๋ฒ”์œ„๋ฅผ ๊ฐ€์ง„๋‹ค.

ReactNode๋Š” ReactChild ์™ธ์—๋„ boolean, null ๋“ฑ ๋” ๋„“์€ ๋ฒ”์ฃผ์˜ ํƒ€์ž…์„ ํฌํ•จํ•œ๋‹ค.

ReactNode๋Š” ๋ฆฌ์•กํŠธ์˜ render ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ํ˜•ํƒœ๋ฅผ ๋‹ด๊ณ  ์žˆ๋‹ค.

 

JSX.Element

declare global {
  namespace JSX {
    interface Element extends React.ReactElement<any, any> {
      //...
    }
    //...
  }
}

JSX.Element๋Š” ReactElement์˜ ์ œ๋„ค๋ฆญ์œผ๋กœ props์™€ ํƒ€์ž… ํ•„๋“œ์— ๋Œ€ํ•ด any ํƒ€์ž…์„ ๊ฐ€์ง€๋„๋ก ํ™•์žฅํ•˜๊ณ  ์žˆ๋‹ค.

JSX.Element๋Š” ReactElement์˜ ํŠน์ • ํƒ€์ž…์œผ๋กœ props์™€ ํƒ€์ž… ํ•„๋“œ๋ฅผ any๋กœ ๊ฐ€์ง€๋Š” ํƒ€์ž…์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

 

๋ฆฌ์•กํŠธ์—์„œ ๊ธฐ๋ณธ HTML ์š”์†Œ ํƒ€์ž… ํ™œ์šฉํ•˜๊ธฐ

 

DetailedHTMLProps์™€ ComponentWithoutRef

HTML ํƒœ๊ทธ ์†์„ฑ ํƒ€์ž…์„ ํ™œ์šฉํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ํƒ€์ž… 2๊ฐœ๋Š” ๋ฆฌ์•กํŠธ์˜ DetailedHTMLProps์™€ ComponentPropsWithoutRef ํƒ€์ž…์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ

React.DetailedHTMLProps๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” HTML ํƒœ๊ทธ ์†์„ฑ๊ณผ ํ˜ธํ™˜๋˜๋Š” ํƒ€์ž…์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.

type NativeButtonProps = React.DetailedHTMLProps<
  React.ButtonHTMLAttributes<HTMLButtonElement>,
  HTMLButtonElement
>;

type ButtonProps = {
  onClick?: NaticeButtonProps["onClick"]
};

 

type NativeButtonType = React.ComponentPropsWithoutRef<"button">;
type ButtonProps = {
  onClick?: NativeButtonType["onClick"];
};

 

 

โœจ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

JSX๋กœ ๊ตฌํ˜„๋œ Select ์ปดํฌ๋„ŒํŠธ

const Select = ({ onChange, options, selectedOption }) => {
  const handlechange = (e) => {
    const selected = Object.entries(options)
      .find(([_, value]) => value === e.target.value)?.[0];
    onChange?. (selected);
  };

  return (
    <select
      onChange={handlechange}
      value={selectedOption 8& options[selectedOption]}
    >
      {Object.entries(options).map(([key, value]) => (
        <option key={key} value={value}>
          {value}
        </option>
      ))}
    </select>
  );
};

์œ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๊ฐ option์˜ ํ‚ค-๊ฐ’ ์Œ์„ ๊ฐ์ฒด๋กœ ๋ฐ›๊ณ  ์žˆ์œผ๋ฉฐ ์„ ํƒ๋œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ฐ›๋„๋ก ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ ์†์„ฑ์— ์–ด๋–ค ํƒ€์ž…์˜ ๊ฐ’์„ ์ „๋‹ฌํ•ด์•ผ ํ• ์ง€ ๋ช…ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ์ถ”๊ฐ€์ ์ธ ์„ค๋ช…์ด ํ•„์š”ํ•˜๋‹ค.

 

 

JSDocs๋กœ ์ผ๋ถ€ ํƒ€์ž… ์ง€์ •ํ•˜๊ธฐ

์ปดํฌ๋„ŒํŠธ์˜ ์†์„ฑ ํƒ€์ž…์„ ๋ช…์‹œํ•˜๊ธฐ ์œ„ํ•ด JSDocs๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

JSDocs๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์„ค๋ช…๊ณผ ๊ฐ ์†์„ฑ์ด ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ๊ฐ„๋‹จํ•˜๊ฒŒ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‹ค.

/**
  * Select ์ปดํฌ๋„ŒํŠธ
  * @param {Object} props - Select ์ปดํฌ๋„ŒํŠธ๋กœ ๋„˜๊ฒจ์ฃผ๋Š” ์†์„ฑ
  * @param {Object} props.options - { [key๏ผš string]๏ผš string } ํ˜•์‹์œผ๋กœ ์ด๋ฃจ์–ด์ง„ option ๊ฐ์ฒด
  * @param {string | undefined} props.selectedOption - ํ˜„์žฌ ์„ ํƒ๋œ option์˜ key๊ฐ’
  (optional)
  * @param {function} props.onChange - select ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ๋ถˆ๋ฆฌ๋Š” callBack ํ•จ์ˆ˜
  (optional)
  * @returns {JSX.Element}
  */
const Select = //...

 

 

props ์ธํ„ฐํŽ˜์ด์Šค ์ ์šฉํ•˜๊ธฐ

JSDocs๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๊ฐ ์†์„ฑ์˜ ๋Œ€๋žต์ ์ธ ํƒ€์ž…๊ณผ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ options๊ฐ€ ์–ด๋–ค ํ˜•์‹์˜ ๊ฐ์ฒด๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š”์ง€๋‚˜ onChange์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ ๋ฐ˜ํ™˜ ๊ฐ’์— ๋Œ€ํ•œ ๊ตฌ์ฒด์ ์ธ ์ •๋ณด๋ฅผ ์•Œ๊ธฐ ์‰ฝ์ง€ ์•Š์•„ ์ž˜๋ชป๋œ ํƒ€์ž…์ด ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ๋Š” ์œ„ํ—˜์ด ์กด์žฌํ•œ๋‹ค.

์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ์ข€ ๋” ์ •๊ตํ•˜๊ณ  ๊ตฌ์ฒด์ ์ธ ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋ฆฌ์•กํŠธ ์ด๋ฒคํŠธ

๋ฆฌ์•กํŠธ๋Š” ๊ฐ€์ƒ DOM์„ ๋‹ค๋ฃจ๋ฉด์„œ ์ด๋ฒคํŠธ๋„ ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

DOM ์—˜๋ฆฌ๋จผํŠธ์— ๋“ฑ๋ก๋˜์–ด ์ฒ˜๋ฆฌํ•˜๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ์™€ ๋‹ฌ๋ฆฌ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์— ๋“ฑ๋ก๋˜๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ์™€ ๋‹ฌ๋ฆฌ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์— ๋“ฑ๋ก๋˜๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋Š” ์นด๋ฉœ ์ผ€์ด์Šค๋กœ ํ‘œ๊ธฐํ•œ๋‹ค.

๋ฆฌ์•กํŠธ ์ด๋ฒคํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ๊ณ ์œ ํ•œ ์ด๋ฒคํŠธ์™€ ์™„์ „ํžˆ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.

 

ํ›…์— ํƒ€์ž… ์ถ”๊ฐ€ํ•˜๊ธฐ

useState ๊ฐ™์€ ํ•จ์ˆ˜ ์—ญ์‹œ ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ง€์ •ํ•ด ์คŒ์œผ๋กœ์จ ๋ฐ˜ํ™˜๋˜๋Š” state ํƒ€์ž…์„ ์ง€์ •ํ•ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ๋ช…์‹œํ•˜์ง€ ์•Š์œผ๋ฉด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ดˆ๊นƒ๊ฐ’์˜ ํƒ€์ž…์„ ๊ธฐ๋ฐ˜์œผ๋กœ state ํƒ€์ž…์„ ์ถ”๋ก ํ•œ๋‹ค.

type Fruit = keyof typeof fruits; // 'apple' | 'banana' | 'blueberry';
const [fruit, changeFruit] = useState<Fruit | undefined>("apple");
// ์—๋Ÿฌ ๋ฐœ์ƒ
const func = () => {
changeFruit ("orange”);
};

keyof typeof obj๋Š” ํ•ด๋‹น ๊ฐ์ฒด์˜ ํ‚ค๊ฐ’์„ ์œ ๋‹ˆ์˜จ ํƒ€์ž…์œผ๋กœ ์ถ”์ถœํ•˜๋Š” ํŒจํ„ด์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉ๋œ๋‹ค.

ํ›…์ด๋‚˜ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” ๋‚ด๋ถ€ ๋ชจ๋“ˆ์˜ ํ•จ์ˆ˜๋Š” ์ ์ ˆํ•œ ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ์„ค์ •ํ•ด ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ œ๋„ค๋ฆญ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

const FruitSelect = () => {
  const [fruit, changeFruit] = useState<Fruit | undefined>();
  
  return (
    <Select onChange={changeFruit} options={fruits} selectedOption="orange" />
  );
};

selectedOption์€ options์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฐ’์„ ๋ฐ›์•„๋„ ์•„๋ฌด๋Ÿฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ์—ญ์‹œ ํ•จ์ˆ˜๋ผ์„œ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

interface SelectProps<OptionType extends Record<string, string>> {
  options: OptionType;
  selectedOption?: keyof OptionType;
  onChange?: (selected?: keyof OptionType) => void;
}

const Select = <OptionType extends Record<string, string>>({
  options,
  selectedOption,
  onChange,
}: SelectProps<OptionType>) => {
  // Select component implementation
};

์œ„ ์ฝ”๋“œ์—์„œ๋Š” ๊ฐ์ฒด ํ˜•์‹์˜ ํƒ€์ž…์„ ๋ฐ›์•„ ํ•ด๋‹น ๊ฐ์ฒด์˜ ํ‚ค๊ฐ’์„ selectedOption, onChange์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์—๋งŒ ์ ์šฉํ•˜๋„๋ก ๋งŒ๋“  ์˜ˆ์‹œ๋‹ค.

Select ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋˜๋Š” props์˜ ํƒ€์ž… ๊ธฐ๋ฐ˜์œผ๋กœ ํƒ€์ž…์ด ์ถ”๋ก ๋˜์–ด <Select<์ถ”๋ก ๋œ ํƒ€์ž…>> ํ˜•ํƒœ์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

 

HTMLAttributes, ReactProps ์ ์šฉํ•˜๊ธฐ

className, id์™€ ๊ฐ™์€ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ๊ธฐ๋ณธ props๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด SelectProps์— ์ง์ ‘ className?: string; id?: string;์„ ๋„ฃ์–ด๋„ ๋˜์ง€๋งŒ ๋ฆฌ์•กํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ๋” ์ •ํ™•ํ•œ ํƒ€์ž…์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

type ReactSelectProps = React.ComponentPropsWithoutRef<"select">;

interface SelectProps<OptionType extends Record<sring, string>> {
  id?: ReactSelectProps["id"];
  className?: ReactSelectProps["className"];
  //...
}

ComponentPropsWithoutRef๋Š” ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์˜ prop ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” ํƒ€์ž…์ด๋‹ค.

Type['key']๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๊ฐ์ฒด ํ˜•์‹์˜ ํƒ€์ž… ๋‚ด๋ถ€ ์†์„ฑ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

ReactProps์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํƒ€์ž…์„ ๊ฐ€์ ธ์™€์•ผ ํ•œ๋‹ค๋ฉด Pick ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๊ณต๋ณ€์„ฑ๊ณผ ๋ฐ˜๊ณต๋ณ‘์„ฑ

์ผ๋ฐ˜์ ์ธ ํƒ€์ž…๋“ค์€ ๊ณต๋ณ€์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ์ข์€ ํƒ€์ž…์—์„œ ๋„“์€ ํƒ€์ž…์œผ๋กœ ํ• ๋‹น์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

ํ•˜์ง€๋งŒ ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ์ง€๋‹Œ ํ•จ์ˆ˜๋Š” ๋ฐ˜๊ณต๋ณ€์„ฑ์„ ๊ฐ€์ง„๋‹ค.

์•ˆ์ „ํ•œ ํƒ€์ž… ๊ฐ€๋“œ๋ฅผ ์œ„ํ•ด ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฐ˜๊ณต๋ณ€์ ์ธ ํ•จ์ˆ˜ ํƒ€์ž…์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋œ๋‹ค.

 

 

728x90