๐โโ๏ธ ํ ์ค(Hooks)๋,
ํจ์ ์ปดํฌ๋ํธ์์ ์ฌ์ฉ ๋ถ๊ฐ๋ฅํ ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋์ ํ๊ณ์ ์ผ๋ก ์ธํด ์ํ ๊ด๋ฆฌ ๋ฐ ๋ ๋๋ง ์ดํ ์์ ์ปจํธ๋กค ๋ฑ ๋ค์ํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ง๋ ํจ์ ์งํฉ
๐โโ๏ธ useState์ด๋,
React ๊ฐ์ฒด ๋ด๋ถ์ ์กด์ฌํ๋ ํจ์ํ ์์ฑ
React.useState()
ํํ๋ก ํธ์ถํด์ ์ฌ์ฉํด์ผํ์ง๋ง ๊ตฌ์กฐ๋ถํดํ ๋น์ ์ด์ฉํ์ฌ ๋ฏธ๋ฆฌ ์ ์ญ ๋ณ์๋ก ์ ์ธํด๋๊ณ ๋๋ฉด React.๋ฅผ ์๋ตํ๊ณ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์ด๋,
์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ํ์ ๋น๋๊ธฐ ์์ ์ด๋ ๋ถ์ ํจ๊ณผ(side effect)๋ฅผ ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ฃผ๋ Hook
- useEffect๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ ๋๋ง ์งํ, ์ ๋ฐ์ดํธ ์งํ ํธ์ถ ๋จ
- ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋๊ธฐ ์ง์ , ์ ๋ฐ์ดํธ ๋๊ธฐ ์ง์ ์ ์คํํ ๋ด์ฉ์ด ์๋ค๋ฉด ์ ๋ฆฌ(clean-up)๋ฅผ ํ๋ ๊ธฐ๋ฅ๋ ์ํ ๊ฐ๋ฅ
- ์ด์ effect ๋ด์ฉ์ ์ ๋ฆฌํ๊ณ ๋ ๋ค ์๋ก์ด effect๊ฐ ๋์ํ๋๋ก ํ ๋ ์ฌ์ฉ
- ์ด์ effect๊ฐ ๋จ์์๋ ์ํ์์ ์๋ก์ด effect๊ฐ ๋ฐ์ํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์๋ ์ถฉ๋์ด ๋ฐ์ํ ๊ฐ๋ฅ์ฑ ์์
- componentWillUnmount์ ์ญํ ๊ณผ ๋์ผ
<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>
<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>
<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๋,
๋ค์ํ ์ปดํฌ๋ํธ์ state๋ฅผ ์ ๋ฐ์ดํธ ํ ๋ ์ฌ์ฉํ๋ Hook
- Reducer ์ฌ์ฉ ์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ ์ปดํฌ๋ํธ ์ ๋ฐ์ดํธ ๋ก์ง์ ์ปดํฌ๋ํธ ๋ฐ์ผ๋ก ๋ถ๋ฆฌํ ์ ์๋ค๋ ์
- Reducer๋ ์๋ก์ด ์ํ๋ฅผ ๋ง๋ค ๋ ๋ฐ๋์ ๋ถ๋ณ์ฑ์ ์ง์ผ์ค์ผํจ (๊ธฐ์กด state์ ๊ฐ์ ๋ณ๊ฒฝํ๋๊ฒ ์๋๋ผ ์๋กญ๊ฒ ์์ฑ)
<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>
<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๋?
์ฐ์ฐ์ผ๋ก ์ป์ ๊ฐ ์์ฒด๋ฅผ ๊ธฐ์ต(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์ด๋,
ํจ์๋ฅผ ์บ์ฑํ์ฌ ๋ถํ์ํ ๋ ๋๋ง์ ๋ฐฉ์งํ๋ Hook
๐โ useMemo์ useCallback์ ์ฐจ์ด์
- useMemo๋ Memoization๋ ๊ฐ์ ๋ฐํํ๋ ํจ์
- useCallback์ Memoization๋ ๊ฐ์ด ์๋ ํจ์๋ฅผ ๋ฐํํ๋ ํจ์
- useMemo๋ ํจ์๋ฅผ ์คํํด์ ๊ทธ ์คํ ๊ฐ์ ๋ฐํํ์ง๋ง, 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>
const printNumber = ()=> {
console.log(`current number : ${ number }`);
}
/* printNumber๊ฐ ๋ณ๊ฒฝ ๋ ๋๋ง ํธ์ถ ๋๋๋ก ํ๋ ์๋๋ก ์์ฑํ์ง๋ง printNumber ํจ์๋ ๊ฐ์ฒด์ด๊ณ ,
App์ ์ฌํธ์ถ ํ ๋๋ง๋ค ์ด๊ธฐํ๊ฐ ๋๊ธฐ ๋๋ฌธ์ toggle์ ๋ณ๊ฒฝํ ๋๋ printNumber๊ฐ ๋ถํ์ํ๊ฒ ์ด๊ธฐํ๊ฐ ๋ค์ ์ผ์ด๋จ */
useEffect(()=> {
console.log('printNumber ํจ์ ๋ณ๊ฒฝ!');
}, [printNumber]);
/* ํจ์ ์์ฑ์ด ๋ถํ์ํ๊ฒ ๊ณ์ ๋ ๋ useCallback์ ์ด์ฉํ์ฌ ํจ์๋ฅผ memorizationํด์ ์ฌ์ฉ ๊ฐ๋ฅ */
const printNumber = useCallback(()=> {
console.log(`current number : ${ number }`);
}, [number]); // number๊ฐ ๋ณ๊ฒฝ๋์์ ๋๋ง ์ด ํจ์๋ฅผ ๋ค์ ์คํํ์ฌ printNumber์ ๋ด์
// ๋น ๋ฐฐ์ด๋ก ์์ฑ ์ ์ต์ด ๋ก๋ฉ๋ ๋ ํ ๋ฒ ํจ์ ์์ฑ ํ ๊ณ์ ์ฌ์ฉํ๋ค๋ ์๋ฏธ
/* useCallback์ ํ์ฉํ๊ธฐ๋๋ฌธ์ ์ค์ง number๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง userEffect ์คํ */
useEffect(()=> {
console.log('printNumber ํจ์ ๋ณ๊ฒฝ!');
}, [printNumber]);
<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์ด๋,
ํจ์ํ ์ปดํฌ๋ํธ์์ DOM ์์์ ์ง์ ์ ๊ทผํ๊ฑฐ๋, ์ปดํฌ๋ํธ ๋ด๋ถ์์ ์ฌ์ฉํ๋ ๋ณ์ ๊ฐ์ ๊ด๋ฆฌํ ์ ์๋๋ก ํ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ Hook
<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>
<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๋,
๋ถ๋ชจ ์ปดํฌ๋ํธ์์ ์์ฑํ Context ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์์ ์ปดํฌ๋ํธ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ Hook
์ปดํฌ๋ํธ ํฉ์ฑ์ ํตํด ํธ๋ฆฌ ๊ตฌ์กฐ๊ฐ ๋ณต์กํด์ง์๋ก ํ์ ์ปดํฌ๋ํธ๋ก props๋ฅผ ์ ๋ฌํ๊ธฐ ์ํด drilling ๋ฐ์ ๊ฐ๋ฅ์ฑ์ด ์์. ์ด ๋ ์ ์ง๋ณด์ ๋ฐ ์ฝ๋ ์ฝ๊ธฐ๊ฐ ์ด๋ ค์์ง๋ ๋ฌธ์ ๊ฐ ์กด์ฌ.
context๋ React ์ปดํฌ๋ํธ ํธ๋ฆฌ ์์ ์ ์ญ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ์ ์๋๋ก ๊ณ ์๋ ๋ฐฉ๋ฒ์ผ๋ก context๋ฅผ ์ฌ์ฉํ๋ฉด ์ค๊ฐ ์๋ฆฌ๋จผํธ๋ค์๊ฒ props๋ฅผ ๋๊ฒจ์ฃผ์ง ์์๋ ๋๊ณ , ์ ์ง๋ณด์๋ ์์ํด์ง.
๋จ, ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ์ ์ด๋ ค์์ด ์๊ธด๋ค๋ ๋ฌธ์ ๊ฐ ์๊ธฐ ๋๋ฌธ์ ํ์ํ ๋๋ง ์ฌ์ฉ
<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>
<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์ด๋,
ํน์ ์ํ๊ด๋ฆฌ๋ ๋ผ์ดํ์ฌ์ดํด ๋ก์ง๋ค์ ์ถ์ํํ์ฌ ๋ฌถ์ด์ ์ฌ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋๋ก ์ ์ํ ์ฌ์ฉ์ ์ ์ ํจ์
<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>