ํ›…์Šค(Hooks)

JOY๐ŸŒฑยท2023๋…„ 4์›” 19์ผ
0

๐Ÿณ React

๋ชฉ๋ก ๋ณด๊ธฐ
2/5
post-thumbnail

๐Ÿ’โ€โ™€๏ธ ํ›…์Šค(Hooks)๋ž€,
ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์†Œ๋“œ์˜ ํ•œ๊ณ„์ ์œผ๋กœ ์ธํ•ด ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐ ๋ Œ๋”๋ง ์ดํ›„ ์‹œ์  ์ปจํŠธ๋กค ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ํ•จ์ˆ˜ ์ง‘ํ•ฉ


๐Ÿ‘€ useState

๐Ÿ’โ€โ™€๏ธ useState์ด๋ž€,
React ๊ฐ์ฒด ๋‚ด๋ถ€์— ์กด์žฌํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ์†์„ฑ

  • React.useState() ํ˜•ํƒœ๋กœ ํ˜ธ์ถœํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผํ•˜์ง€๋งŒ ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น์„ ์ด์šฉํ•˜์—ฌ ๋ฏธ๋ฆฌ ์ „์—ญ ๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•ด๋‘๊ณ  ๋‚˜๋ฉด React.๋ฅผ ์ƒ๋žตํ•˜๊ณ  useState()๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

1) useState์˜ ์‚ฌ์šฉ

<body>

    <div id="root"></div>

    <script type="text/babel">

        function Say() {

            /* message๋ผ๋Š” ์ƒํƒœ์™€ setter ๋ฉ”์†Œ๋“œ๋ฅผ ๋ฐฐ์—ด ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น์œผ๋กœ ํ• ๋‹นํ•œ ๋’ค
            message๋ฅผ '์น˜์ฆˆ ์ฑ„ํŒ…๋ฐฉ๐Ÿง€'(์ดˆ๊ธฐ๊ฐ’)์œผ๋กœ ์ดˆ๊ธฐํ™” */
            const [message, setMessage] = useState('์น˜์ฆˆ ์ฑ„ํŒ…๋ฐฉ๐Ÿง€');

            /* ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ƒํƒœ๋“ค์„ ํ•œ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ์‚ฌ์šฉํ•ด๋„ ๋จ */
            const [color, setColor] = useState('block');
            const [backgroundColor, setBackgroundColor] = useState('white');

            const onClickEnter = ()=> setMessage('Hi!๐Ÿคฉ');
            const onClickLeave = ()=> setMessage('Bye~๐Ÿฅน');

            return (
                <>
                    <h1 style={{ color, backgroundColor }}>{ message }</h1> {/* value๊ฐ€ key์™€ ๊ฐ™๋‹ค๋ฉด ์ƒ๋žต ๊ฐ€๋Šฅ */}
                    <div>
                        <button onClick={ onClickEnter }>์ž…์žฅ</button>
                        <button onClick={ onClickLeave }>ํ‡ด์žฅ</button>
                    </div>
                    <div>
                        <button onClick={ ()=> setColor('#fef3a4') }>๋…ธ๋ž€์ƒ‰</button>
                        <button onClick={ ()=> setColor('#fed0bd') }>๋ถ„ํ™์ƒ‰</button>
                        <button onClick={ ()=> setColor('#bdf1fe') }>ํŒŒ๋ž€์ƒ‰</button>
                    </div>
                    <div>
                        <button onClick={ ()=> setBackgroundColor('white')}>Light mode</button>
                        <button onClick={ ()=> setBackgroundColor('black')}>Dark mode</button>
                    </div>
                </>
            );
        }


        ReactDOM.createRoot(document.getElementById("root")).render(<Say />);

    </script>
    
</body>


๐Ÿ‘€ useEffect

๐Ÿ’โ€โ™€๏ธ useEffect์ด๋ž€,
์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ํ›„์— ๋น„๋™๊ธฐ ์ž‘์—…์ด๋‚˜ ๋ถ€์ˆ˜ ํšจ๊ณผ(side effect)๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” Hook

  • useEffect๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ Œ๋”๋ง ์งํ›„, ์—…๋ฐ์ดํŠธ ์งํ›„ ํ˜ธ์ถœ ๋จ
  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ ํ•ด์ œ ๋˜๊ธฐ ์ง์ „, ์—…๋ฐ์ดํŠธ ๋˜๊ธฐ ์ง์ „์— ์‹คํ–‰ํ•  ๋‚ด์šฉ์ด ์žˆ๋‹ค๋ฉด ์ •๋ฆฌ(clean-up)๋ฅผ ํ•˜๋Š” ๊ธฐ๋Šฅ๋„ ์ˆ˜ํ–‰ ๊ฐ€๋Šฅ
  • ์ด์ „ effect ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๊ณ  ๋‚œ ๋’ค ์ƒˆ๋กœ์šด effect๊ฐ€ ๋™์ž‘ํ•˜๋„๋ก ํ•  ๋•Œ ์‚ฌ์šฉ
  • ์ด์ „ effect๊ฐ€ ๋‚จ์•„์žˆ๋Š” ์ƒํƒœ์—์„œ ์ƒˆ๋กœ์šด effect๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋‚˜ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ ์žˆ์Œ
  • componentWillUnmount์˜ ์—ญํ• ๊ณผ ๋™์ผ

1) useEffect์˜ ์‚ฌ์šฉ

<body>

    <div id="root"></div>

    <script type="text/babel">

        const { useState, useEffect } = React;

        function App() {

            const [count, setCount] = useState(1);
            const [name, setName] = useState('');

            const handleCountUpdate = ()=> {
                setCount(count + 1);
            };

            const handleInputChange = (e)=> {
                setName(e.target.value);
            }

            /* --------------------------------------------------------------------- */

            /* ๋ Œ๋”๋ง(mount&update) ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋˜๋Š” useEffect */
            useEffect(()=> {
                console.log('๋ Œ๋”๋ง(mount&update) ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๐Ÿ’ฉ');
            }); 

            /* mount / [count]๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ์‹คํ–‰๋˜๋Š” useEffect */
            useEffect(()=> {
                console.log('mount๊ฐ€ ๋˜๊ฑฐ๋‚˜ count์˜ ๋ณ€ํ™”๐Ÿคฉ');
                /* UPDATE ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด์ง€ ์•Š์•„๋„ input๋ฐ•์Šค ์•ˆ์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค useEffect๋Š” ๊ณ„์† ์‹คํ–‰๋˜๋ฏ€๋กœ ๋น„ํšจ์œจ์  
                   => ๋”ฐ๋ผ์„œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ๋งŒ ๋ Œ๋”๋ง์ด ๋˜๋„๋ก(name์•„ ์•„๋‹Œ count์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ useEffect ์‹คํ–‰๋˜๋„๋ก) ํ•˜๊ธฐ */
            }, [count]); /* []์•ˆ์— count๋ฅผ ์ „๋‹ฌํ•ด์คŒ์œผ๋กœ์จ ์ด์ œ๋ถ€ํ„ฐ๋Š” mount๊ฐ€ ๋˜๊ฑฐ๋‚˜ count์˜ ๊ฐ’์ด ๋ณ€ํ™”๋  ๋•Œ๋งŒ ์ด useEffect๊ฐ€ ์‹คํ–‰๋  ๊ฒƒ */

            /* mount / [name]์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ์‹คํ–‰๋˜๋Š” useEffect */
            useEffect(()=> {
                console.log('mount๊ฐ€ ๋˜๊ฑฐ๋‚˜ name์˜ ๋ณ€ํ™”๐Ÿคก');
            }, [name]); 

            /* update๋ฅผ ์ œ์™ธํ•˜๊ณ  mount๊ฐ€ ๋  ๋•Œ๋งŒ ์‹คํ–‰๋˜๋Š” useEffect */
            useEffect(()=> {
                console.log('mounting๐Ÿค–๐Ÿค–๐Ÿค–')
            }, []); 

            /* --------------------------------------------------------------------- */

            return (
                <>
                    <button onClick={ handleCountUpdate }>UPDATE</button><br/>
                    <span>count: { count }</span><br/>
                    <input type="text" value={ name } onChange={ handleInputChange }/>
                    <span>์ด๋ฆ„ : { name }</span>
                </>
            );
        }

        ReactDOM.createRoot(document.getElementById("root")).render(<App />);

    </script>
    
</body>

2) clean-up

<body>

    <div id="root"></div>

    <script type="text/babel">

        const { useState, useEffect } = React;

        /* Timer ์ปดํฌ๋„ŒํŠธ */
        function Timer({}) {

            useEffect(()=> {
                /* ์ด๊ณณ์— ์ž‘์„ฑํ•œ setInterval()์„ ์ •๋ฆฌํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด, unmount๋˜์–ด๋„ ํƒ€์ด๋จธ๋Š” ๋ฉˆ์ถ”์ง€ ์•Š์Œ */
                const timer = setInterval(()=> {
                    console.log(`ํƒ€์ด๋จธ ๋Œ์•„๊ฐ€๋Š”์ค‘.. ${new Date().toLocaleTimeString()}`);
                }, 1000);

                /* unmount๋˜์—ˆ์„ ๋•Œ ํƒ€์ด๋จธ๋ฅผ ๋ฉˆ์ถ”๋ ค๋ฉด return๊ตฌ๋ฌธ์— clearInterval()์„ ์ž‘์„ฑํ•˜์—ฌ ์ •๋ฆฌํ•˜๊ธฐ */
                return () => {
                    clearInterval(timer);
                    console.log('ํƒ€์ด๋จธ ์ •์ƒ ์ข…๋ฃŒ!');
                };

            }, []);

            return (
                <>
                    <span>ํƒ€์ด๋จธ ์‹œ์ž‘! ์ฝ˜์†” ํ™•์ธ :)</span>
                </>
            );
        }

        function App() {

            const [showTimer, setShowTimer] = useState(false);

            return (
                <>
                    {showTimer && <Timer />} {/* : showtimer๊ฐ€ true์ผ ๋•Œ๋งŒ Timer ์ปดํฌ๋„ŒํŠธ ์‹คํ–‰ */}
                    <button onClick={ ()=> setShowTimer(!showTimer)}>Toggle Timer</button> {/* ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋ฐ˜์ „ */}
                </>
            );
        }

        ReactDOM.createRoot(document.getElementById("root")).render(<App />);

    </script>
    
</body>

3) useEffect์˜ ํ™œ์šฉ

<body>

    <div id="root"></div>

    <script type="text/babel">

        const { useState, useEffect } = React;

        function TypingGame({ text, isDone, setIsDone }) {

            console.log('TypingGame์ด ๋ Œ๋”๋ง ๋˜๋Š” ์ˆœ๊ฐ„โœจ')

            const [input, setInput] = useState('');

            useEffect(
                ()=> {
                    const start = new Date().getTime(); // mount๋˜๊ณ ๋‚œ ์งํ›„์˜ ์‹œ๊ฐ„์ด start์— ๋‹ด๊น€

                    return ()=> {
                        const end = new Date().getTime(); // unmount๋˜๊ธฐ ์ง์ „์˜ ์‹œ๊ฐ„์ด end์— ๋‹ด๊น€

                        const interval = end - start;
                        alert(`โฐ${ interval }(ms)โฐ`);
                    }
                },
                []
            );

            const onKeyPressHandler = (e)=> {
                console.log('onKeyPressHandler๊ฐ€ ํ˜ธ์ถœ ๋˜๋Š” ์ˆœ๊ฐ„โœจ')

                if(e.key === 'Enter') {
                    if(text === input) {    // ์ œ์‹œ๋œ text์™€ input์— ์ž…๋ ฅ๋œ ๊ฐ’(๋ฌธ์ž์—ด)์ด ๊ฐ™์„ ๋•Œ
                        setIsDone(!isDone); // isDone์˜ ๊ฐ’ ๋ฐ˜์ „ (์•„๋ž˜์˜ isShow๊ฐ€ ๋ฐ”๋€œ) 
                        console.log('isDone์ด ๋ฐ˜์ „๋˜๋Š” ์ˆœ๊ฐ„โœจ')
                    }
                }
            };

            return (
                <>
                    <h1>{ text }</h1>
                    <input
                        type="text"
                        value={ input }
                        onChange={ (e)=> setInput(e.target.value) } // input๋ฐ•์Šค ์•ˆ์˜ ์ƒํƒœ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ์ด๋ฒคํŠธ
                        onKeyPress={ onKeyPressHandler }
                    />

                </>
            );
        }

      /* ------------------------------------------------------------------------- */
      
        function App() {

            const [isShow, setIsShow] = useState(false);
            const [isDone, setIsDone] = useState(false);
            const [text, setText] = useState('');

            console.log(`isShow๋Š”? : ${isShow}`);
            console.log(`isDone๋Š”? : ${isDone}`);
            console.log(`text๋Š”? : ${text}`);

            useEffect(
                ()=> {
                    console.log('prompt์ฐฝ์— ๋ฌธ์ž๋ฅผ ์ž…๋ ฅํ•˜๋Š” ์ˆœ๊ฐ„โœจ')
                    setText(prompt('์ œ์‹œํ•  ๋ฌธ์ž์—ด ์ž…๋ ฅ :)'));
                },
                [] // ์ตœ์ดˆ ์‹คํ–‰ ์‹œ์—๋งŒ ์ž‘๋™ํ•˜๋ฉด ๋˜๋ฏ€๋กœ mount์‹œ์—๋งŒ ์ž‘๋™ํ•˜๋„๋ก ์„ค์ •
            );

            useEffect(
                ()=> {
                    setIsShow(!isShow);
                    console.log('isShow๊ฐ€ ๋ฐ˜์ „๋˜๋Š” ์ˆœ๊ฐ„โœจ')
                },
                [isDone] // isDone์˜ ๊ฐ’์ด ๋ณ€ํ™”ํ–ˆ์„ ๋•Œ isShow์˜ ๊ฐ’์„ ๋ฐ˜์ „์‹œ์ผœ(๋ฐ”๋กœ ์œ„์˜ setIsShow()์‹คํ–‰) ๋ Œ๋”๋ง ๋˜๋Š” ๋™์ž‘์„ ๋ฐ”๊ฟˆ
            );

            return (
                <>
                    { isShow && <TypingGame text={ text } isDone={ isDone } setIsDone={ setIsDone }/>}
                </>
            );
        }

        ReactDOM.createRoot(document.getElementById("root")).render(<App />);

    </script>
    
</body>


๐Ÿ‘€ useReducer

๐Ÿ’โ€โ™€๏ธ useReducer๋ž€,
๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ์˜ state๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” Hook

  • Reducer ์‚ฌ์šฉ ์‹œ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ ์ปดํฌ๋„ŒํŠธ ์—…๋ฐ์ดํŠธ ๋กœ์ง์„ ์ปดํฌ๋„ŒํŠธ ๋ฐ–์œผ๋กœ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ 
  • Reducer๋Š” ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋งŒ๋“ค ๋•Œ ๋ฐ˜๋“œ์‹œ ๋ถˆ๋ณ€์„ฑ์„ ์ง€์ผœ์ค˜์•ผํ•จ (๊ธฐ์กด state์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑ)

1) useReducer์˜ ์‚ฌ์šฉ

<body>
    
    <div id="root"></div>

    <script type="text/babel">

        const { useReducer } = React;

        /* reducer() ํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” ๊ธฐ์กด ์ƒํƒœ ๊ฐ’,
        ๋‘ ๋ฒˆ์งธ ์ธ์ž๋Š” ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋‹ด์€ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌ ๋ฐ›์Œ */
        function reducer(state, action) { /* action : ํ•˜๊ณ ์žํ•˜๋Š” ๋™์ž‘์ด ๋ฌด์—‡์ธ์ง€ ํƒ€์ž…์„ ์ž‘์„ฑ */
            /* ์—…๋ฐ์ดํŠธ๋ฅผ ํ•  ๋•Œ ์‚ฌ์šฉ ๋  ํ•จ์ˆ˜ */

            /* action์— ์ „๋‹ฌ ๋œ type์— ๋”ฐ๋ผ ์ƒˆ๋กœ์šด state๋ฅผ ๊ฐฑ์‹ ํ•  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฆฌํ„ด (๋ถˆ๋ณ€์„ฑ ์œ ์ง€) */
            switch(action.type) {
                case 'INCREMENT' : return { value : state.value + 1}; // ์ฆ๊ฐ€ ๋™์ž‘
                case 'DECREMENT' : return { value : state.value - 1}; // ๊ฐ์†Œ ๋™์ž‘
                default : return state; // ์•„๋ฌด ํƒ€์ž…์— ํ•ด๋‹นํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ๊ธฐ์กด state ๋ฐ˜ํ™˜

            }
        }

        function Counter() {

            /* useReducer์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” Reducerํ•จ์ˆ˜,
            ๋‘ ๋ฒˆ์งธ ์ธ์ž๋Š” ํ•ด๋‹น Reducer์˜ ๊ธฐ๋ณธ ๊ฐ’ */
            /* state๋Š” ํ˜„์žฌ ์ƒํƒœ์ด๊ณ  dispatcher๋Š” action์„ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ํ•จ์ˆ˜ */
            const [state, dispatcher] = useReducer(reducer, { value : 0 });

            return (
                <>
                    <h1>count : { state.value }</h1> {/* ๊ธฐ๋ณธ๊ฐ’ 0์ด ํ™”๋ฉด์— ๋…ธ์ถœ */}
                    <button onClick={ ()=> dispatcher({ type : 'DECREMENT' }) }>1๐Ÿ”ป</button>
                    <button onClick={ ()=> dispatcher({ type : 'INCREMENT' }) }>1๐Ÿ”บ</button>
                </>
            );
        }

        ReactDOM.createRoot(document.getElementById("root")).render(<Counter />);
    </script>
    
</body>

2) form์—์„œ์˜ useReducer ์‚ฌ์šฉ

<body>
    
    <div id="root"></div>

    <script type="text/babel">

        /* Reducer๋ฅผ ํ™œ์šฉํ•ด input ์ž…๋ ฅ ๊ฐ’ ์ƒํƒœ ๊ด€๋ฆฌ */

        const { useReducer } = React;

        function reducer(state, action) {
            /* ์ƒˆ๋กœ์šด ๊ฐ์ฒด ๋งŒ๋“ค์–ด์„œ ๋ฐ˜ํ™˜ => state์— ์ด๊ฒƒ์ด ์—…๋ฐ์ดํŠธ */
            return { ...state, [action.name] : action.value }; // action.name ์ฒ˜๋Ÿผ '์†์„ฑ(ex:name)'์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ๋Š” [] ์‚ฌ์šฉ
        }

        function RegistForm() {

            const [state, dispatcher] = useReducer(reducer, { // ๋‘ ๋ฒˆ์งธ ์ธ์ž์— name, nickname
                name : '',
                nickname : ''
            });

            const { name, nickname } = state; // state.name / state.nickname ๋Œ€์‹  ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น

            /* change ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด reducer๋กœ ์ด๋ฒคํŠธ ๋ฐœ์ƒ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌ */
            const onChangeHandler = e => dispatcher(e.target);

            return (
                <>
                    <label>์ด๋ฆ„ : </label>
                    <input type="text" name="name" value={ name } onChange={ onChangeHandler }/><br/>
                    <label>๋‹‰๋„ค์ž„ : </label>
                    <input type="text" name="nickname" value={ nickname } onChange={ onChangeHandler }/><br/>
                    <h3>์ž…๋ ฅํ•œ ์ด๋ฆ„ : { name }</h3>
                    <;h3>์ž…๋ ฅํ•œ ๋‹‰๋„ค์ž„ : { nickname }</h3>
                </>
            );
        };

        ReactDOM.createRoot(document.getElementById("root")).render(<RegistForm />);
    </script>

</body>


๐Ÿ‘€ useMemo

1) useMemo์˜ ์‚ฌ์šฉ

๐Ÿ’โ€โ™€๏ธuseMemo๋ž€?
์—ฐ์‚ฐ์œผ๋กœ ์–ป์€ ๊ฐ’ ์ž์ฒด๋ฅผ ๊ธฐ์–ต(memorize) ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” hook

  • ๊ฐ„๋‹จํ•œ ์ž‘์—…์„ ํ•  ๋•Œ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์„ ํ•จ๊ป˜ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋น„ํšจ์œจ์ .
    ์—ฐ์‚ฐ์„ ํ†ตํ•ด ๋‚˜์˜จ ๊ฐ’์„ ๋ฉ”๋ชจ๋ฆฌ์ƒ์— ์ €์žฅํ•ด๋‘๊ณ , ํ•ด๋‹น ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์„ ๋•Œ๋Š” ๋‹ค์‹œ ์—ฐ์‚ฐํ•˜์ง€ ์•Š๋„๋ก ํ•จ
<body>
    
    <div id="root"></div>

    <script type="text/babel">

        const { useState, useMemo } = React;

        const hardCalculator = (number)=> {
            console.log('์–ด๋ ค์šด ๊ณ„์‚ฐ');
            for(let i = 0; i < 999999999; i++) {
                // blank - ์‹œ๊ฐ„๊ณผ ๋น„์šฉ์ด ๋“œ๋Š” ๊ณ„์‚ฐ์ด๋ผ๋Š” ์˜๋ฏธ
            }

            return number + 10000;
        };

        const easyCalculator = (number)=> {
            console.log('์‰ฌ์šด ๊ณ„์‚ฐ');

            return number + 1;
        }
        
        function App() {

            const [hardNumber, setHardNumber] = useState(1);
            const [easyNumber, setEasyNumber] = useState(1);

            /* ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•œ ํ›„ ๋ฐ˜ํ™˜ ๋ฐ›๋Š” ๊ฐ’์„ ๋ฆฌํ„ด ๊ฐ’ ํ˜•ํƒœ๋กœ ์ž‘์„ฑ
            ๋‘ ๋ฒˆ์งธ ์ธ์ž๋Š” ์˜์กด์„ฑ ๋ฐฐ์—ด์ด๋ผ๊ณ  ํ•˜๋Š”๋ฐ, ์˜์กด์„ฑ ๋ฐฐ์—ด์— ๋“ฑ๋กํ•œ ๊ฐ’์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€
            ๋งŒ์•ฝ ๋นˆ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์•„๋ฌด๊ฒƒ๋„ ๊ฐ์ง€ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ฒซ ๋กœ๋”ฉ ์‹œ์—๋งŒ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐ’์„ ๊ธฐ์–ตํ•จ */
            // hardNumber / easyNumber์˜ ๋ณ€ํ™”๊ฐ€ ์—†์œผ๋ฉด return๋ฌธ์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์–ตํ•ด๋‘” ๊ฐ’ ์‚ฌ์šฉ 
            const hardNum = useMemo(()=> { return hardCalculator(hardNumber) }, [hardNumber]); 
            const easyNum = useMemo(()=> { return easyCalculator(easyNumber) }, [easyNumber]);
            

            return (
                <>  
                    <h3>์–ด๋ ค์šด ๊ณ„์‚ฐ๊ธฐ</h3>
                    <input 
                        type="number" 
                        value={ hardNumber }
                        onChange={ (e)=> setHardNumber(parseInt(e.target.value)) }
                    />
                    <span> + 10000 = { hardNum }</span>
                    <h3>์‰ฌ์šด ๊ณ„์‚ฐ๊ธฐ</h3>
                    <input 
                        type="number" 
                        value={ easyNumber }
                        onChange={ (e)=> setEasyNumber(parseInt(e.target.value)) }
                    />
                    <span> + 1 = { easyNum }</span>
                </>
            );
        }

      
      ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
</body>


๐Ÿ‘€ useCallback

๐Ÿ’โ€โ™€๏ธ useCallback์ด๋ž€,
ํ•จ์ˆ˜๋ฅผ ์บ์‹ฑํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๋Š” Hook


๐Ÿ™‹โ€ useMemo์™€ useCallback์˜ ์ฐจ์ด์ 

  • useMemo๋Š” Memoization๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
  • useCallback์€ Memoization๋œ ๊ฐ’์ด ์•„๋‹Œ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
    • useMemo๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด์„œ ๊ทธ ์‹คํ–‰ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ, useCallback์€ ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ๋ฐ˜ํ™˜

1) useCallback์˜ ์‚ฌ์šฉ

<body>

    <div id="root"></div>
    
    <script type="text/babel">

        const { useState, useEffect, useCallback } = React;

        function App() {

            const [number, setNumber] = useState(0);
            const [toggle, setToggle] = useState(false);

            /* ํ•จ์ˆ˜ ์ƒ์„ฑ์ด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๊ณ„์† ๋  ๋•Œ useCallback์„ ์ด์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ memorizationํ•ด์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ */
            const printNumber = useCallback(()=> {
                console.log(`current number : ${ number }`);
            }, [number]); // number๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋งŒ ์ด ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ printNumber์— ๋‹ด์Œ
            // ๋นˆ ๋ฐฐ์—ด๋กœ ์ž‘์„ฑ ์‹œ ์ตœ์ดˆ ๋กœ๋”ฉ๋  ๋•Œ ํ•œ ๋ฒˆ ํ•จ์ˆ˜ ์ƒ์„ฑ ํ›„ ๊ณ„์† ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์˜๋ฏธ

            
            /* useCallback์„ ํ™œ์šฉํ–ˆ๊ธฐ๋•Œ๋ฌธ์— ์˜ค์ง number๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ userEffect ์‹คํ–‰ */
            useEffect(()=> {
                console.log('printNumber ํ•จ์ˆ˜ ๋ณ€๊ฒฝ!');
            }, [printNumber]);


            return (
                <>
                    <input
                        type="number"
                        value={ number }
                        onChange={ (e)=> setNumber(e.target.value) }
                    />
                    <button
                        onClick={ ()=> setToggle(!toggle) }
                    >
                        { toggle.toString() }
                    </button>
                    <button 
                        onClick={ printNumber }
                    >
                        printNumberState
                    </button>
                </>
            );
        }

        ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
    
</body>

๐Ÿ‘‰ useCallback์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ์˜ ๋ฌธ์ œ์ 

			const printNumber = ()=> {
                console.log(`current number : ${ number }`);
            } 

            /* printNumber๊ฐ€ ๋ณ€๊ฒฝ ๋  ๋•Œ๋งŒ ํ˜ธ์ถœ ๋˜๋„๋ก ํ•˜๋Š” ์˜๋„๋กœ ์ž‘์„ฑํ–ˆ์ง€๋งŒ printNumber ํ•จ์ˆ˜๋Š” ๊ฐ์ฒด์ด๊ณ ,
            App์„ ์žฌํ˜ธ์ถœ ํ•  ๋•Œ๋งˆ๋‹ค ์ดˆ๊ธฐํ™”๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์— toggle์„ ๋ณ€๊ฒฝํ•  ๋•Œ๋„ printNumber๊ฐ€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์ดˆ๊ธฐํ™”๊ฐ€ ๋‹ค์‹œ ์ผ์–ด๋‚จ */
            useEffect(()=> {
                console.log('printNumber ํ•จ์ˆ˜ ๋ณ€๊ฒฝ!');
            }, [printNumber]);

๐Ÿ‘‰ useCallback ์‚ฌ์šฉ ํ›„ ํ•ด๊ฒฐ

 			/* ํ•จ์ˆ˜ ์ƒ์„ฑ์ด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๊ณ„์† ๋  ๋•Œ useCallback์„ ์ด์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ memorizationํ•ด์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ */
            const printNumber = useCallback(()=> {
                console.log(`current number : ${ number }`);
            }, [number]); // number๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋งŒ ์ด ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ printNumber์— ๋‹ด์Œ
            // ๋นˆ ๋ฐฐ์—ด๋กœ ์ž‘์„ฑ ์‹œ ์ตœ์ดˆ ๋กœ๋”ฉ๋  ๋•Œ ํ•œ ๋ฒˆ ํ•จ์ˆ˜ ์ƒ์„ฑ ํ›„ ๊ณ„์† ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์˜๋ฏธ

            
            /* useCallback์„ ํ™œ์šฉํ–ˆ๊ธฐ๋•Œ๋ฌธ์— ์˜ค์ง number๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ userEffect ์‹คํ–‰ */
            useEffect(()=> {
                console.log('printNumber ํ•จ์ˆ˜ ๋ณ€๊ฒฝ!');
            }, [printNumber]);

2) ์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ์—์„œ์˜ useCallback

<body>

    <div id="root"></div>
    
    <script type="text/babel">

        const { useState, useEffect, useCallback } = React;

        function App() {

            const [size, setSize] = useState(200);
            const [isDark, setIsDark] = useState(false);

            /* Square ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌํ•  ํ•จ์ˆ˜ */
            const genSquareStyle = useCallback( // size๊ฐ€ ์•„๋‹Œ isDark๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ค์ง€ ์•Š๋„๋ก useCallback๊ณผ ์˜์กด์„ฑ ๋ฐฐ์—ด [size] ์‚ฌ์šฉ
                ()=> {
                    return {
                        backgroundColor : '#c2e3f9',
                        width : `${ size }px`,
                        height : `${ size }px`
                    }
                }, [size]
            );

            return (
                <>
                    <div style={{ backgroundColor : isDark ? 'black' : 'white' }}>
                        <input
                            type="range"
                            min="100"
                            max="300"
                            value={ size }
                            onChange={ (e) => setSize(e.target.value) }
                        />
                        <button 
                            onClick={ ()=> setIsDark(!isDark) }
                        >
                            { isDark.toString() }
                        </button>
                        <Square genSquareStyle={ genSquareStyle } /> {/* ๋งŒ๋“  ํ•จ์ˆ˜ ์ „๋‹ฌ */}
                    </div>
                </>
            );

        }

        function Square({ genSquareStyle }) {

            // style์ด ๋ฐ”๋€๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด ๋ฆฌ๋ Œ๋”๋ง ํ•˜์ง€ ์•Š๋„๋ก ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด state ์ƒ์„ฑ
            const [style, setStyle] = useState({});

            useEffect(
                ()=> {
                    console.log(`Style ๋ณ€๊ฒฝ!`)
                    setStyle(genSquareStyle()); // ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด๊ฐ€ setStyle์— ์ €์žฅ
                }, [genSquareStyle] // genSquareStyle๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋งŒ useEffect ์‹คํ–‰
            )

            return (
                <div style={ style }></div>
            );
        }

        ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>

</body>


๐Ÿ‘€ useRef

๐Ÿ’โ€โ™€๏ธ useRef์ด๋ž€,
ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ DOM ์š”์†Œ์— ์ง์ ‘ ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜, ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ณ€์ˆ˜ ๊ฐ’์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” Hook

1) ์ง€์—ญ ๋ณ€์ˆ˜ ์‚ฌ์šฉ ์‹œ useRef์˜ ํ™œ์šฉ

<body>

    <div id="root"></div>
    
    <script type="text/babel">

        const { useState, useRef } = React;

        function Counter() {

            const [count, setCount] = useState(0);
            let variable = 0;
            const countRef = useRef(0); // current : 0 ์ด๋ผ๋Š” ๊ฐ์ฒด๋กœ ๋ฐ˜ํ™˜๋ฐ›์Œ

            console.log('Counter ๋ Œ๋”๋ง ~')

            const increaseCount = ()=> {
                setCount(count + 1);
            };

            /* useRef๊ฐ€ ์•„๋‹Œ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ํ•จ์ˆ˜ */
            const increaseVariable = ()=> {
                variable += 1;
                console.log(`variable : ${variable}`) 
                // varible์„ ๋ณ€๊ฒฝ์‹œํ‚ค๊ณ  ๋ Œ๋”๋ง์ด ๋œ ํ›„ ๋‹ค์‹œ ์ฒดํฌํ•˜๋ฉด ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ๋Œ์•„๊ฐ€์žˆ์Œ
                // ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ๊ฐ’์„ ๊ธฐ์–ตํ•˜์ง€ ๋ชป ํ•˜๊ณ  ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์–ด์žˆ๋Š” ๊ฒƒ
            }

            /* useRef๋ฅผ ์‚ฌ์šฉํ•œ ํ•จ์ˆ˜ */
            const increaseCountRef = ()=> {
                countRef.current = countRef.current + 1;
                console.log(`current : ${countRef.current}`) 
                // ์œ„์˜ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ์™€๋Š” ๋‹ฌ๋ฆฌ, ๋‹ค์‹œ ๋ Œ๋”๋ง์ด ๋˜์–ด๋„ 
                // useRef๋ฅผ ํ™œ์šฉํ•œ ๊ฐ’์€ ๊ธฐ์–ต๋˜์–ด ์ฝ˜์†”์— ์ถœ๋ ฅ๋˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธ
            }

            return (
                <>
                    <h1> count : { count }</h1>
                    <h1> variable : { variable }</h1>
                    <h1> countRef.current : { countRef.current }</h1>
                    <button onClick={ increaseCount }>count ์ฆ๊ฐ€</button>
                    <button onClick={ increaseVariable }>variable ์ฆ๊ฐ€</button>
                    <button onClick={ increaseCountRef }>countRef.current ์ฆ๊ฐ€</button>
                </>
            );

        }

        ReactDOM.createRoot(document.getElementById("root")).render(<Counter />);
    </script>
    
</body>

2) ํŠน์ • input์— focus๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•œ useRef์˜ ํ™œ์šฉ

<body>

    <div id="root"></div>

    <script type="text/babel">

        const { useState, useEffect, useRef } = React;

        function LoginComponent() {

            /* ํ•˜๋‚˜์˜ state๋กœ ๋ฌถ์–ด์„œ ๊ด€๋ฆฌ */
            const [form, setForm] = useState({
                id : '',
                pwd : ''
            })

            const idRef = useRef();
            console.log(idRef); // ๋ Œ๋”๋ง ์ด์ „ ๋™์ž‘์ด๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ดˆ ์ถœ๋ ฅ์€ undefined

            useEffect(()=> {
                // ์ดˆ๊ธฐ ํ™”๋ฉด ๋ Œ๋”๋ง ํ›„ ์ถœ๋ ฅ ํ™•์ธ
                console.log(idRef);
                // ํฌ์ปค์Šค ์„ค์ •
                idRef.current.focus(); // idRef.current : ๊ธฐ์–ตํ•ด๋†”์•ผํ•˜๋Š” ๊ฐ’์ด ์žˆ์„ ๋–„ ์ด๋Ÿฐ ์‹์œผ๋กœ ์‚ฌ์šฉ
            }, []);

            const onChangeHandler = (e)=> {
                setForm({...form, [e.target.name] : e.target.value})
            } 

            return (
                <>
                    <input
                        type="text"
                        name="id"
                        ref={ idRef } /* ์—ฐ๊ฒฐํ•จ์œผ๋กœ์จ ์ฐธ์กฐ ๊ฐ€๋Šฅ */
                        placeholder="id"
                        value={ form.id }
                        onChange={ onChangeHandler }
                    />
                    <br/>
                    <input
                        type="password"
                        name="pwd"
                        placeholder="password"
                        value={ form.pwd }
                        onChange={ onChangeHandler }
                    />
                    <br/>
                    <button>๋กœ๊ทธ์ธ</button>
                </>
            );
        }
      
        ReactDOM.createRoot(document.getElementById("root")).render(<LoginComponent />);
    </script>
    
</body>


๐Ÿ‘€ useContext

๐Ÿ’โ€โ™€๏ธ useContext๋ž€,
๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์„ฑํ•œ Context ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž์‹ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” Hook
์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ์„ ํ†ตํ•ด ํŠธ๋ฆฌ ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•ด์งˆ์ˆ˜๋ก ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ props๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด drilling ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ. ์ด ๋•Œ ์œ ์ง€๋ณด์ˆ˜ ๋ฐ ์ฝ”๋“œ ์ฝ๊ธฐ๊ฐ€ ์–ด๋ ค์›Œ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์กด์žฌ.
context๋Š” React ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ์•ˆ์— ์ „์—ญ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ณ ์•ˆ๋œ ๋ฐฉ๋ฒ•์œผ๋กœ context๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ค‘๊ฐ„ ์—˜๋ฆฌ๋จผํŠธ๋“ค์—๊ฒŒ props๋ฅผ ๋„˜๊ฒจ์ฃผ์ง€ ์•Š์•„๋„ ๋˜๊ณ , ์œ ์ง€๋ณด์ˆ˜๋„ ์ˆ˜์›”ํ•ด์ง.
๋‹จ, ์ปดํฌ๋„ŒํŠธ ์žฌ์‚ฌ์šฉ์— ์–ด๋ ค์›€์ด ์ƒ๊ธด๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•„์š”ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉ

1) ๋‹คํฌ๋ชจ๋“œ (non-useContext)

<body>

    <div id="root"></div>
    
    <script type="text/babel">

        const { useState } = React;

        function Header({ isDark }) {

            return (
                <header
                    className="header"
                    style={
                        {
                            backgroundColor : isDark ? 'black' : 'lightgray',
                            color : isDark ? 'white' : 'black'
                        }
                    }
                >
                    <h1>WELCOME TO CHEESE WORLD</h1>
                </header>
            );
        }

        function Content({ isDark }) {

            return (
                <div
                    className="content"
                    style={
                        {
                            backgroundColor : isDark ? 'black' : 'white',
                            color : isDark ? 'white' : 'black'
                        }
                    }
                >
                    <p>์น˜์ฆˆ ํ•œ ์ž…๐Ÿง€</p>
                    <p>์น˜์ฆˆ ๋‘ ์ž…๐Ÿง€๐Ÿง€</p>
                    <p>์น˜์ฆˆ ์„ธ ์ž…๐Ÿง€๐Ÿง€๐Ÿง€</p>
                </div>
            );
        }

        function Footer({ isDark, setIsDark }) {

            const toggleHandler = () => setIsDark(!isDark);

            return (
                <footer
                    className="footer"
                    style={
                        {
                            backgroundColor : isDark ? 'black' : 'white',
                            color : isDark ? 'white' : 'black'
                        }
                    }
                >
                    <button onClick={ toggleHandler }>{ isDark ? 'Light Mode๐ŸŒž' : 'Dark Mode๐ŸŒ' }</button>
                    Copyright 2023. Cheese. all rights reserved.
                </footer>
            );
        }

        function Page({ isDark, setIsDark }) {

            return (
                <div className="page">
                    <Header isDark={ isDark }/>
                    <Content isDark={ isDark }/>
                    <Footer isDark={ isDark } setIsDark={ setIsDark }/> {/* Footer์—์„œ ๋‹คํฌ๋ชจ๋“œ๋ฅผ ์„ค์ •ํ•  ๊ฒƒ์ด๋ฏ€๋กœ setIsDark๊นŒ์ง€ ๋ณด๋‚ด์คŒ */}
                </div>
            );
        }

        function App() {

            const [isDark, setIsDark] = useState(false);

            return <Page isDark={ isDark } setIsDark={ setIsDark }/>
        }

        
        ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
    
</body>

2) ๋‹คํฌ๋ชจ๋“œ (useContext)

<body>

    <div id="root"></div>
    
    <script type="text/babel">

        const { useState, createContext, useContext } = React;

        /* context ๊ฐ์ฒด ์ƒ์„ฑ
        ์ธ์ž๋กœ defaultValue ์ „๋‹ฌ, defaultValue๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ null ์„ค์ • 
        context ๊ฐ์ฒด๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•  ๋•Œ React๋Š” ํŠธ๋ฆฌ ์ƒ์œ„์— ๊ฐ€์žฅ ๊ฐ€๊นŒ์ด ์žˆ๋Š” provider๋กœ ๋ถ€ํ„ฐ ํ˜„์žฌ ๊ฐ’์„ ์ฝ์–ด๋“ค์ž„
        ์ด๋•Œ ์ ์ ˆํ•œ Provider๋ฅผ ์ฐพ์ง€ ๋ชป ํ•  ๋•Œ ์“ฐ์ด๋Š” ๊ฐ’์ด defaultValue */
        const DarkModeContext = createContext(null); // ๊ณต์šฉ ์ €์žฅ์†Œ ์ƒ์„ฑ!

        function Header() {

            /* ๊ตฌ๋…! */
            const context = useContext(DarkModeContext);
            const { isDark } = context;

            return (
                <header
                    className="header"
                    style={
                        {
                            backgroundColor : isDark ? 'black' : 'lightgray',
                            color : isDark ? 'white' : 'black'
                        }
                    }
                >
                    <h1>WELCOME TO CHEESE WORLD</h1>
                </header>
            );
        }

        function Content() {

            /* ๊ตฌ๋…! */
            const context = useContext(DarkModeContext);
            const { isDark } = context;

            return (
                <div
                    className="content"
                    style={
                        {
                            backgroundColor : isDark ? 'black' : 'white',
                            color : isDark ? 'white' : 'black'
                        }
                    }
                >
                    <p>์น˜์ฆˆ ํ•œ ์ž…๐Ÿง€</p>
                    <p>์น˜์ฆˆ ๋‘ ์ž…๐Ÿง€๐Ÿง€</p>
                    <p>์น˜์ฆˆ ์„ธ ์ž…๐Ÿง€๐Ÿง€๐Ÿง€</p>
                </div>
            );
        }

        function Footer() {

            /* ๊ตฌ๋…! */
            const context = useContext(DarkModeContext);
            const { isDark, setIsDark } = context;

            const toggleHandler = () => setIsDark(!isDark);

            return (
                <footer
                    className="footer"
                    style={
                        {
                            backgroundColor : isDark ? 'black' : 'white',
                            color : isDark ? 'white' : 'black'
                        }
                    }
                >
                    <button onClick={ toggleHandler }>{ isDark ? 'Light Mode๐ŸŒž' : 'Dark Mode๐ŸŒ' }</button>
                    Copyright 2023. Cheese. all rights reserved.
                </footer>
            );
        }

        function Page() {

            return (
                <div className="page">
                    <Header />
                    <Content />
                    <Footer /> 
                </div>
            );
        }

        function App() {

            const [isDark, setIsDark] = useState(false);
            /* Provider๋Š” context๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์—๊ฒŒ context์˜ ๋ณ€ํ™”๋ฅผ ์•Œ๋ฆฌ๋Š” ์—ญํ• 
            Provider๋Š” value prop์„ ์ด์šฉํ•˜์—ฌ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ๊ฐ’์„ ์ „๋‹ฌ
            ์ด ๋•Œ ๊ฐ’์„ ์ „๋‹ฌ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ ์ˆ˜์—๋Š” ์ œํ•œ์ด ์—†์Œ
            prop ํ•˜์œ„์—์„œ 'context๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋Š” value prop์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ๋ Œ๋”๋ง' ๋จ */
            /* useContext๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด props๋กœ ๋‚ด๋ฆฌ์ง€ ์•Š๊ณ  createContext๋กœ ๋งŒ๋“  Context.Provider๋ฅผ ์ด์šฉํ•˜์—ฌ
            value์— ์ €์žฅํ•˜๊ณ  ์•Œ๋ฆฌ๊ณ  ์‹ถ์€ ๊ฐ’์„ ๋„ฃ๊ธฐ */
            return (
                <DarkModeContext.Provider value={{ isDark, setIsDark }}>
                    <Page />
                </DarkModeContext.Provider>
            );
        }

        
        ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    </script>
    
</body>


๐Ÿ‘€ custom-hook

๐Ÿ’โ€โ™€๏ธ custom-hook์ด๋ž€,
ํŠน์ • ์ƒํƒœ๊ด€๋ฆฌ๋‚˜ ๋ผ์ดํ”„์‚ฌ์ดํด ๋กœ์ง๋“ค์„ ์ถ”์ƒํ™”ํ•˜์—ฌ ๋ฌถ์–ด์„œ ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์ œ์ž‘ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜

1) custom-hook์œผ๋กœ 'useInput' ์ •์˜

<body>
    <div id="root"></div>
    
    <script type="text/babel">

        /* ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์„ ๊ณต์œ ํ•  ๊ฒฝ์šฐ,
        ์‚ฌ์šฉ์ž ์ •์˜ custom hook์„ ์ž‘์„ฑํ•˜์—ฌ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ */

        const { useState } = React;

        /* ๋ฐ˜๋ณต๋˜๋Š” ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๋ฌถ์€ ํ•จ์ˆ˜ ์ •์˜ (custom-hook) */
        function useInput() {

            const [value, setValue] = useState('');
            const onChange = (e)=> setValue(e.target.value);

            return { value, onChange };
        }

        function App() {

            /* useInput()์„ ํ˜ธ์ถœํ•˜๊ณ  ๊ฐ๊ฐ ๋‹ค๋ฅธ { value, onChange }๋ฅผ ๋ฐ›์Œ */
            const username = useInput();
            const password = useInput();
            const email = useInput();

            console.log(username);
            console.log(password);
            console.log(email);
            
            return (
                <div>
                    <label>์ด๋ฆ„ : </label>
                    <input type="text" id="username" value={ username.value } onChange={ username.onChange }/>    
                    <br/>     
                    <label>๋น„๋ฐ€๋ฒˆํ˜ธ : </label>
                    <input type="password" id="password" { ...password } /> {/* { ...password }๋Š” value={ password.value } onChange={ password.onChange } ์™€ ๊ฐ™์Œ */}
                    <br/>
                    <label>์ด๋ฉ”์ผ : </label>
                    <input type="email" id="email" {...email} />
                    <br/>
                    <h4>usename : { username.value }</h4>
                    <h4>password : { password.value }</h4>
                    <h4>email : { email.value }</h4>
                </div>
            );

        }

        ReactDOM.createRoot(document.getElementById("root")).render(<App />);

    </script>

profile
Tiny little habits make me

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