React.FC์— ๋Œ€ํ•˜์—ฌ

React.FC์— ๋Œ€ํ•˜์—ฌ

Nov 27, 2022

๊น€ํ˜„๊ธฐ

#REACT

๋“ค์–ด๊ฐ€๋ฉฐ

์ฒ˜์Œ React + typescript ์กฐํ•ฉ์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

// Parent
type Props = {
  count: number;
};

const Parent: React.FC<Props> = ({ count }) => {
  return <div>Parent {count}</div>;
};

export default Parent;


// App
import Parent from "./Parent";

function App() {
  return (
    <div className="App">
      <Parent count={10} />
    </div>
  );
}

export default App;

๊ฐ•์˜๋‚˜ ์—ฌ๋Ÿฌ ์˜ˆ์ œ์—์„œ React.FC๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— โ€œํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ React.FC๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ๋˜๋Š”๊ตฌ๋‚˜โ€๋ผ๋Š” ์ƒ๊ฐ์„ ๊ฐ–๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ์š”

์ตœ๊ทผ์— React.FC ์‚ฌ์šฉ์„ ์ œํ•œํ•˜๋Š” ์ถ”์„ธ๋‹ค.๋ผ๋Š” ๊ธ€ ์„ ๋ณด๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฌด์Šจ์ผ ์ธ๊ณ  ๊ถ๊ธˆํ•˜๋‹ˆ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด๋ฉด์„œ ์•Œ์•„๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ ธ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ ๋‚ด์šฉ ์ œ๋ชฉ์€ ์ œ๊ฐ€ ์ง์—ญ์„ ํ•ด์„œ ์–ด์ƒ‰ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์–‘ํ•ด ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ผ๋ฐ˜ ํ•จ์ˆ˜์™€ ๋‹ค๋ฅธ ์ 

1. React.FunctionComponentย is explicit about the return type, while the normal function version is implicit (or else needs additional annotation).

React.FunctionComponent๋Š” ๋ช…์‹œ์ ์ด๋‹ค. ๋ฐ˜ํ™˜ํ•˜๋Š” type์— ๋Œ€ํ•ด์„œ. ๋ฐ˜๋ฉด์— ์ผ๋ฐ˜ ํ•จ์ˆ˜ ๋ฒ„์ „์€ ์•”์‹œ์ ์ด๋‹ค ํ˜น์€ ์ถ”๊ฐ€๋กœ annotation(ํƒ€์ž… ์ง€์ •)์ด ํ•„์š”ํ•˜๋‹ค.

*annotation์ด ํ•„์š”ํ•˜๋‹ค.

React.FunctionComponent๊ฐ€ ๋ช…์‹œ์ ์ด๋ž€ ๋ง์ด ๋ฌด์Šจ ๋œป์ผ๊นŒ์š”? vscode๋ฅผ ์ผœ๊ณ  React.FC์— ์–ด๋–ค ํƒ€์ž…์ด ์ง€์ •๋˜์–ด ์žˆ๋Š”์ง€ ๋“ค์–ด๊ฐ€ ๋ดค์Šต๋‹ˆ๋‹ค.

type FC<P = {}> = FunctionComponent<P>;

interface FunctionComponent<P = {}> {
	(props: P, context?: any): ReactElement<any, any> | null;
	propTypes?: WeakValidationMap<P> | undefined;
	contextTypes?: ValidationMap<any> | undefined;
	defaultProps?: Partial<P> | undefined;
	displayName?: string | undefined;
}

@types/react์— React.FC์˜ 5๊ฐ€์ง€ type์ด ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

2. It provides typechecking and autocomplete for static properties likeย โ€˜displayNameโ€™,ย โ€˜propTypesโ€™, andย โ€˜defaultPropsโ€™.

displayName๊ณผ propTypes ๊ทธ๋ฆฌ๊ณ  defaultProps์™€ ๊ฐ™์€ ์ •์  ํ”„๋กœํผํ‹ฐ๋ฅผ ์œ„ํ•œ ์ž๋™์™„์„ฑ๊ณผ typechecking์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด prop๋“ค์ด ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋Š”์ง€ ํ•œ๋ฒˆ ์•Œ์•„๋ด…์‹œ๋‹ค.

1. displayName

type Props = {
  count: number;
};

const Parent: React.FC<Props> = ({ count }) => {
  return <div>Parent {count}</div>;
};

Parent.displayName = "Hello World";

export default Parent;

display๋Š” ๋ฌธ์„œ์—์„œ ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ์š” React.Component โ€“ React ์ผ๋ฐ˜์ ์œผ๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ ๋””๋ฒ„๊น…์šฉ์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

2. propTypes, defaultProps

Typechecking With PropTypes โ€“ React

propTypes์™€ defaultProps๋Š” ๋ฌธ์„œ์— ์นœ์ ˆํ•˜๊ฒŒ ์„ค๋ช…๋˜์–ด ์žˆ๋Š”๋ฐ defaultProps๋Š” ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ณธ๊ฐ’์„ ์ •์˜ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๊ณต์‹ ๋ฌธ์„œ ์˜ˆ์ œ๋Š” ํด๋ž˜์Šค ํ˜•์œผ๋กœ ๋˜์–ด์žˆ์ง€๋งŒ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์ฒด ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉ

type Props = {
  count: number;
  myName?: string;
};

const Parent = ({ count, myName = "hyunki" }: Props) => {
  return (
    <div>
      Parent {myName} {count}
    </div>
  );
};
์ด๋Ÿฐ defaultProps๊ฐ€ React.FC์—์„œ ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์™œ ๊ทธ๋Ÿฐ์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์˜ˆ์ œ๋Š” ์ œ๊ฐ€ ๋งŒ๋“  ์˜ˆ์ œ๋กœ ์กฐ๊ธˆ ๋ฐ”๊ฟ”๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

React.FC๋กœ ์ •์˜ํ•˜์ง€ ์•Š์Œ

type Props = {
  count: number;
  // ์œ„ ์˜ˆ์ œ์—์„œ๋Š” optional๋กœ ์ฃผ์—ˆ์ง€๋งŒ defaultProps๋ฅผ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.
  myName: string;
};

const Parent = ({ count, myName }: Props) => {
  return (
    <div>
      Parent {myName} {count}
    </div>
  );
};

Parent.defaultProps = {
  myName: "hyunki",
};

export default Parent;


// App
import Parent from "./Parent";

function App() {
  return (
    <div className="App">
	  // ์—๋Ÿฌ์—†์ด ํŽธ์•ˆํ•จ..
      <Parent count={10} />
    </div>
  );
}

export default App;

React.FC๋กœ ์ •์˜

// Parent
type Props = {
  count: number;
  myName: string;
};

const Parent: React.FC<Props> = ({ count, myName }) => {
  return (
    <div>
      Parent {myName} {count}
    </div>
  );
};

Parent.defaultProps = {
  myName: "hyunki",
};

// App
import Parent from "./Parent";

function App() {
  return (
    <div className="App">
	  // myName ์†์„ฑ์ด ์—†๋‹ค๊ณ  ์—๋Ÿฌ...
      <Parent count={10} />
    </div>
  );
}

export default App;

์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ธ”๋กœ๊ทธ๋‚˜ ํŠธ์œ„ํ„ฐ์—์„œ๋„ hooks์˜ ๋“ฑ์žฅ,

์ด์— ๋”ฐ๋ฅธ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์˜ ์‚ฌ์šฉ ๋“ฑ์œผ๋กœ ์ธํ•˜์—ฌ ์ œ๊ฐ€ ์ฒ˜์Œ์— ์ž‘์„ฑํ•œ ๊ฐ์ฒด ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉ ์„ ๊ถŒ์žฅํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

3. Before theย React 18 type updates,ย โ€˜React.FunctionComponentโ€™ provided an implicit definition ofย โ€˜childrenโ€™ย (see below), which was heavily debated and is one of the reasonsย 

React18 type ์—…๋ฐ์ดํŠธ์ „์—๋Š” React.FunctionComponent๋Š” children์˜ ์ •์˜๋ฅผ ์•”์‹œ์ ์œผ๋กœ ์ œ๊ณต ํ–ˆ์—ˆ๋Š”๋ฐ ์ด๋Š” ๋…ผ๋ž€์ด ๋งŽ์•˜์œผ๋ฉฐ React.FC๊ฐ€ CRA(create-react-app) Typescript์—์„œ ํ…œํ”Œ๋ฆฟ์—์„œ ์‚ญ์ œ๋œ ์ด์œ  ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

children์„ ์•”์‹œ์ ์œผ๋กœ ์ œ๊ณตํ–ˆ๋‹ค..? ์œ„์—์„œ ์ €ํฌ๊ฐ€ ์‚ดํŽด๋ณธ React.FC type์—๋Š” children์€ ์—†์—ˆ๋Š”๋ฐ ์ด๋Ÿฐ children์„ ์•”์‹œ์ ์œผ๋กœ ์ œ๊ณตํ–ˆ๋‹ค๋Š” ๋œป์ผ๊นŒ์š”? ์ฝ”๋“œ๋กœ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.

React 18 ๋ฒ„์ „์—์„œ๋Š” type์˜ค๋ฅ˜๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.

// Parent
type Props = {
  count: number;
  myName?: string;
};

const Parent: React.FC<Props> = ({ count, myName }) => {
  return (
    <div>
      Parent {myName} {count}
    </div>
  );
};

export default Parent;

// App
import Parent from "./Parent";

function App() {
  return (
    <div className="App">
      // IntrinsicAttributes & Props' ํ˜•์‹์— 'children' ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค
      <Parent count={10}>
        <p>๋‚˜๋Š” children ์ž…๋‹ˆ๋‹ค.</p>
      </Parent>
    </div>
  );
}
export default App;

ํ•˜์ง€๋งŒ React17์—์„œ๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋ƒฅ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค. ์˜ค๋ฅ˜๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด typescript๋ฅผ ๋„์ž…ํ•˜๋Š” ์ž…์žฅ์—์„œ ์ด๋Ÿฐ ์ด์Šˆ๋Š” ์กฐ๊ธˆ ํฌ๋ฆฌํ‹ฐ์ปฌ ํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋งˆ์น˜๋ฉฐ

์ง€๊ธˆ๊นŒ์ง€ React.FC ์‚ฌ์šฉ ์ œํ•œ์ด๋ผ๋Š” ๋‚ด์šฉ์„ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค. ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•˜๊ธฐ์— ์ผ๋ฐ˜์ ์œผ๋กœ ์“ฐ์ด๋Š”์ค„ ์•Œ์•˜๊ณ  ๋งŽ์ด ์“ฐ๋˜ React.FC์— ๋Œ€ํ•œ ๋ฐฐ์‹ ๊ฐ(?)๋„ ๋“ค๋ฉด์„œ ํ•œํŽธ์œผ๋กœ๋Š” ๊นŠ๊ฒŒ React๋ฅผ ์‚ฌ์šฉ ํ•ด๋ดค๋‹ค๋ฉด ์ถฉ๋ถ„ํžˆ ์ฒด๊ฐํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ์ด์Šˆ์˜€๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋ฌธ์„œ

Grow & Glow ยฉ 2025

Banner images by undraw.co