๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ‘จ‍๐Ÿ’ป web.dev/fe

React ์ปดํฌ๋„ŒํŠธ(children) ํƒ€์ดํ•‘ํ•˜๊ธฐ

by HandHand 2022. 7. 23.

 

๐Ÿ“Œ ๋ฌด์Šจ ํƒ€์ž…์„ ์จ์•ผํ•˜์ง€..? ๐Ÿค”

TypeScript ์™€ ํ•จ๊ป˜ React ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐœ๋ฐœํ•˜๋‹ค๋ณด๋ฉด ์ปดํฌ๋„ŒํŠธ์—์„œ

children ์„ prop ์œผ๋กœ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•˜๊ณ  ์ด์— ๋Œ€ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •ํ•ด์ค˜์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

 

export default function Component({ children }) {
    return (
        <div>
            ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.
            { children }
        </div>
    )
}

 

์ด๋Ÿด๋•Œ๋งˆ๋‹ค ํ•ญ์ƒ ๊ณ ๋ฏผ์ธ ๋ถ€๋ถ„์ด children ์— ์–ด๋–ค ํƒ€์ž…์„ ๋ช…์‹œํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ธ๊ฐ€? ์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” ์ด ๋ถ€๋ถ„์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์„ ํ•ด๊ฒฐํ•˜๊ณ ์ž!

React ์ปดํฌ๋„ŒํŠธ์˜ children ์— ํ• ๋‹น ๊ฐ€๋Šฅํ•œ ํƒ€์ž…๋“ค์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ React ์—์„œ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ children ํƒ€์ž…๋“ค

1๏ธโƒฃ JSX.Element

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

                // ...        
        }
}

 

JSX.Element ๋Š” ReactElement ๋ฅผ ์ƒ์†๋ฐ›๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค.

์ด๋•Œ ReactElement ์˜ type ๊ณผ props ๊ฐ€ any ํƒ€์ž…์œผ๋กœ ์ •์˜๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์–‘ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ JSX ๋ฅผ ๊ทธ๋“ค๋งŒ์˜ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—

React ๋Š” ์ „์—ญ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์œ„์™€ ๊ฐ™์ด JSX ํƒ€์ž…์„ ์ •์˜ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

2๏ธโƒฃ React.ReactElement

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

 

React.createElement ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ReactElement ์š”์†Œ๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ React ์˜ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น ํƒ€์ž…์€ ์˜ค์ง JSX ์š”์†Œ๋งŒ์„ ๋ฐ›๋„๋ก ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—

๋งŒ์•ฝ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์›์‹œ๊ฐ’์„ ๋ถ€์—ฌํ•˜๋ฉด ํƒ€์ž… ์—๋Ÿฌ๋ฅผ ๋ฑ‰์–ด๋‚ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์›์‹œํƒ€์ž…์€ ReactElement์— ํ• ๋‹น์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค

 

์ด ๋•Œ๋ฌธ์— ๋งŒ์•ฝ ์›์‹œ๊ฐ’์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ณ  JSX ์ปดํŒŒ์ผ๋œ React ์ปดํฌ๋„ŒํŠธ๋งŒ ํ—ˆ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ

ReactElement ๋ฅผ ํ†ตํ•ด children ํƒ€์ž…์„ ์ง€์ •ํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿ˜€

 

3๏ธโƒฃ React.ReactChild (โš ๏ธ deprecated)

type ReactChild = ReactElement | string | number;

 

React 18 ๋ถ€ํ„ฐ ์‚ฌ์šฉ์„ ์ง€์–‘ํ•˜๋Š” ํƒ€์ž…์ž…๋‹ˆ๋‹ค.

ReactElement ๋ฅผ ํฌํ•จํ•˜์—ฌ string ๊ณผ number ํƒ€์ž…์„ ํฌํ•จํ•˜๊ณ ์žˆ์Šต๋‹ˆ๋‹ค.

React ์™€ ์ง์ ‘์ ์œผ๋กœ ์—ฐ๊ด€์ด ์—†๋Š” ํ•ด๋‹น ํƒ€์ž…์„ ์ธ๋ผ์ธํ™”ํ•˜์—ฌ

๋ณด๋‹ค ๋ช…ํ™•ํ•œ ํƒ€์ดํ•‘์„ ํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•œ ์˜๋„๋กœ ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค.

 

4๏ธโƒฃ React.ReactNode

type ReactNode = ReactElement | string | number | ReactFragment | ReactPortal | boolean | null | undefined;

 

๊ฐ€์žฅ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” React ์ปดํฌ๋„ŒํŠธํƒ€์ž…์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ํด๋ž˜์Šคํ˜• ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ @types/react ์— ์ •์˜๋˜์–ด์žˆ๋Š” ReactNode ํƒ€์ž…์— ๋Œ€ํ•œ ๋ช…์„ธ์ž…๋‹ˆ๋‹ค.

 

// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L431

class Component<P, S> {
        // ...

        setState<K extends keyof S>(
            state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
            callback?: () => void
        ): void;

        forceUpdate(callback?: () => void): void;

        render(): ReactNode; // <-- โœ… ReactNode!

        // ...
    }

 

string, number, null, undefined ๋“ฑ์˜ ์›์‹œํƒ€์ž…๋“ค๊ณผ

ReactElement, ReactFragment ๋“ฑ์˜ ํƒ€์ž…์„ ๋ชจ๋‘ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ReactNodeArray ๋Š” deprecated ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งŒ์•ฝ ๋ฐฐ์—ด ํ˜•ํƒœ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด

ReactNode[] ํ˜•ํƒœ๋กœ ํƒ€์ž…์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

 

5๏ธโƒฃ React.PropsWithChildren

type PropsWithChildren<P = unknown> = P & { children?: ReactNode | undefined };

 

React 16 ๋ถ€ํ„ฐ ์ง€์›๋˜๊ธฐ ์‹œ์ž‘ํ•œ ํƒ€์ž…์ž…๋‹ˆ๋‹ค.

ํ•ด๋‹น ํƒ€์ž…์„ ํ†ตํ•ด children ์„ ์„ ํƒ์ ์œผ๋กœ ํฌํ•จํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ํƒ€์ดํ•‘์„ ๊ฐ„์ถ”๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ children ์ด ์˜ต์…”๋„ํ•˜๋‹ค๋ณด๋‹ˆ ๋งŒ์•ฝ ์ปดํฌ๋„ŒํŠธ์˜ children ์ด ํ•„์ˆ˜๊ฐ’์ธ ๊ฒฝ์šฐ์—๋Š”

์ ํ•ฉํ•˜์ง€ ์•Š์€ ํƒ€์ž…์ผ ์ˆ˜๋„ ์žˆ๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐ์ด ๋“œ๋„ค์š” ๐Ÿค”

 

6๏ธโƒฃ React.FC (๐Ÿšจ consider not to use!)

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;
}

 

์ด์ „์—๋Š” ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ํƒ€์ดํ•‘ํ•  ๋•Œ FC ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ํ†ตํ•ด ํ•˜๊ณ ๋Š” ํ–ˆ์Šต๋‹ˆ๋‹ค.

React 17 ์—์„œ๋Š” props ๊ฐ€ PropsWithChildren ๋ผ์„œ children ๊ฐ€ ReactNode ํƒ€์ž…์„ ๊ฐ€์กŒ์ง€๋งŒ

React 18 ๋ถ€ํ„ฐ๋Š” props ์— ๋Œ€ํ•œ ํƒ€์ž…์ด ์ œ๋„ค๋ฆญ์œผ๋กœ ๋ฐ”๋€Œ๋ฉด์„œ ์ง์ ‘ ์ง€์ •ํ•ด์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋งŒ React.FC ์˜ ๊ฒฝ์šฐ ์•”๋ฌต์ ์œผ๋กœ children ์„ ํฌํ•จํ•˜๋Š” ๋“ฑ

์žฅ์ ๋ณด๋‹ค ๋งŽ์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋‹จ์ ๋“ค ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ง€์–‘ํ•˜๊ณ  ์žˆ์–ด

๋‹ค๋ฅธ ํƒ€์ž…๋“ค์„ ํ™œ์šฉํ•ด์„œ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ํƒ€์ž…์„ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ ์ฐธ๊ณ ์ž๋ฃŒ

Using React children prop with TypeScript

ReactNode, ReactChild, ReactElement ํƒ€์ž… ๋น„๊ต

When to use JSX.Element vs ReactNode vs ReactElement?

DefinitelyTyped/types/react at master · DefinitelyTyped/DefinitelyTyped

 

๋ฐ˜์‘ํ˜•

๐Ÿ’ฌ ๋Œ“๊ธ€