๐ก useState
// useState ํจ์ ์ฌ์ฉํ๊ธฐ
import { useState } from "react";
const Counter = () => {
const [value, setValue] = useState(0);
return (
<div>
<p>ํ์ฌ ์นด์ดํฐ ๊ฐ์ {value} ์ด๋ค.</p>
<button onClick={() => setValue(value + 1)}>+1</button>
<button onClick={() => setValue(value - 1)}>-1</button>
</div>
);
};
export default Counter;
- useState ๋ ํ๋์ ์ํ ๊ฐ๋ง ๊ด๋ฆฌํ ์ ์์ผ๋ ์ปดํฌ๋ํธ์์ ๊ด๋ฆฌํด์ผ ํ ์ํ๊ฐ ์ฌ๋ฌ ๊ฐ๋ผ๋ฉด useState ๋ฅผ ์ฌ๋ฌ ๋ฒ ์ฌ์ฉํ๋ฉด ๋๋ค.
- useState(0) ์ด๋ ์ด๊ธฐ๊ฐ์ 0 ์ผ๋ก ํ๊ฒ ๋ค๋ ์๋ฏธ์ด๋ค.
- const [value, setValue] ์์ ์ฒซ ๋ฒ์งธ ์์์ธ value ๋ ์ํ ๊ฐ, ๋ ๋ฒ์งธ ์์์ธ setValue ๋ ์ํ๋ฅผ ์ค์ ํ๋ ํจ์์ด๋ค.
- ์ด ํจ์์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฃ์ด์ ํธ์ถํ๋ฉด(setValue(value+1) ๊ณผ ๊ฐ์ด) ์ ๋ฌ๋ฐ์ ํ๋ผ๋ฏธํฐ๋ก ๊ฐ์ด ๋ฐ๋๊ณ ์ปดํฌ๋ํธ๊ฐ ์ ์์ ์ผ๋ก ๋ฆฌ๋ ๋๋งํ๋ค.
์น ์คํ ํ๋ฉด

useState ์ฌ๋ฌ ๋ฒ ์ฌ์ฉํ๊ธฐ
import { useState } from "react";
const Info = () => {
const [name, setName] = useState("");
const [nickname, setNickname] = useState("");
const onChangeName = (e) => {
setName(e.target.value);
};
const onChangeNickName = (e) => {
setNickname(e.target.value);
};
return (
<div>
<input value={name} onChange={onChangeName} />
<input value={nickname} onChange={onChangeNickName} />
<div>์ด๋ฆ : {name}</div>
<div>๋๋ค์ : {nickname}</div>
</div>
);
};
export default Info;
์น ์คํ ํ๋ฉด

๐ก useEffect
๋ฆฌ์กํธ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ๋๋ง๋ค ํน์ ์์ ์ ์ํํ๋๋ก ์ค์ ํ ์ ์๋ Hook ์ด๋ค. useEffect ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ ๋๋ง๋๊ณ ๋ ์งํ๋ง๋ค ์คํ๋๋ฉฐ, ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ ๋ฐฐ์ด์ ๋ฌด์์ ๋ฃ๋์ง์ ๋ฐ๋ผ ์คํ๋๋ ์กฐ๊ฑด์ด ๋ฌ๋ผ์ง๋ค. ํด๋์ค ํ ์ปดํฌ๋ํธ์ธ componentDidMount ์ componentDidUpdate ๋ฅผ ํฉ์น ํํ๋ก ๋ณด์๋ ๋ฌด๋ฐฉํ๋ค.
import { useState, useEffect } from "react";
const Info = () => {
const [name, setName] = useState("");
const [nickname, setNickname] = useState("");
useEffect(() => {
console.log("๋ ๋๋ง์ด ์๋ฃ๋์์ต๋๋ค.");
console.log({
nickname,
});
}, [nickname]);
const onChangeName = (e) => {
setName(e.target.value);
};
const onChangeNickName = (e) => {
setNickname(e.target.value);
};
return (
<div>
<input value={name} onChange={onChangeName} />
<input value={nickname} onChange={onChangeNickName} />
<div>์ด๋ฆ : {name}</div>
<div>๋๋ค์ : {nickname}</div>
</div>
);
};
export default Info;
useEffect ๋ฅผ ํน์ ๊ฐ์ด ์ ๋ฐ์ดํธ ๋ ๋๋ง ํธ์ถํ๊ณ ์ถ์ผ๋ฉด, useEffect ์ ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋๋ ๋ฐฐ์ด [ ] ์์ ๊ฒ์ฌํ๊ณ ์ถ์ ๊ฐ์ ๋ฃ์ด ์ฃผ๋ฉด ๋๋ค.
useEffect(() => {
console.log("๋ ๋๋ง์ด ์๋ฃ๋์์ต๋๋ค.");
console.log({
nickname,
});
}, [nickname]);
๊ฒ์ฌํ๊ณ ์ ํ๋ ๊ฐ์ nickname ์ผ๋ก ์ค์ ํ๋๋ nickname ์ด ๋ฐ๋ ๋๋ง useEffect ์ ํจ์๋ฅผ ์คํํ๋ ๊ฒ์ผ๋ก ๋ฐ๋์๋ค.
์น ์คํ ํ๋ฉด

useEffect ๋ท์ ๋ฆฌ ํ๊ธฐ
์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋๊ธฐ ์ ์ด๋ ์ ๋ฐ์ดํธ ๋๊ธฐ ์ง์ ์ ์ด๋ ํ ์์ ์ ์ํํ๊ณ ์ถ์ผ๋ฉด useEffect ์์ ๋ท์ ๋ฆฌ(clean up) ํจ์๋ฅผ ๋ฐํํด์ฃผ์ด์ผ ํ๋ค.
// App.js
import React, { useState } from "react";
import Info from "./Info";
const App = () => {
const [visible, setVisible] = useState(false);
return (
<div>
<button
onClick={() => {
setVisible(!visible);
console.log(!visible);
}}
>
{visible ? "์จ๊ธฐ๊ธฐ" : "๋ณด์ด๊ธฐ"}
</button>
<hr />
{visible && <Info />}
</div>
);
};
export default App;
// Info.js
import { useState, useEffect } from "react";
const Info = () => {
const [name, setName] = useState("");
const [nickname, setNickname] = useState("");
useEffect(() => {
console.log("effect");
return () => { // cleanup ํจ์ ๋ฐํ
console.log("unmount");
};
}, []);
const onChangeName = (e) => {
setName(e.target.value);
};
const onChangeNickName = (e) => {
setNickname(e.target.value);
};
return (
<div>
<input value={name} onChange={onChangeName} />
<input value={nickname} onChange={onChangeNickName} />
<div>์ด๋ฆ : {name}</div>
<div>๋๋ค์ : {nickname}</div>
</div>
);
};
export default Info;
๋ ๋๋ง ๋ ๋๋ง๋ค ๋ท์ ๋ฆฌ ํจ์๊ฐ ๊ณ์ ๋ํ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ๋ท์ ๋ฆฌ ํจ์๊ฐ ํธ์ถ๋ ๋๋ ์ ๋ฐ์ดํธ ๋๊ธฐ ์ง์ ์ ๊ฐ์ ๋ณด์ฌ์ค๋ค. ์ธ๋ง์ดํธ(์ปดํฌ๋ํธ๊ฐ DOM ์์ ์ ๊ฑฐ๋๋ ๊ฒ, ์ฌ๊ธฐ์๋ ์จ๊ธฐ๊ธฐ ๋ฒํผ ๋๋ฅผ ๋๋ฅผ ์๋ฏธํ๋ค.) ๋ ๋๋ง ๋ท์ ๋ฆฌ ํจ์๋ฅผ ํธ์ถํ๊ณ ์ถ์ผ๋ฉด useEffect ํจ์์ ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์ ๋น์ด ์๋ ๋ฐฐ์ด์ ๋ฃ์ผ๋ฉด ๋๋ค.
์น ์คํ ํ๋ฉด

๐ก useReducer
useReducer ๋ useState ๋ณด๋ค ๋ ๋ค์ํ ์ปดํฌ๋ํธ ์ํฉ์ ๋ฐ๋ผ ๋ค์ํ ์ํ๋ฅผ ๋ค๋ฅธ ๊ฐ์ผ๋ก ์ ๋ฐ์ดํธ ํด์ฃผ๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ Hook ์ด๋ค. Reducer ๋ ํ์ฌ ์ํ(state), ๊ทธ๋ฆฌ๊ณ ์ ๋ฐ์ดํธ๋ฅผ ์ํด ํ์ํ ์ ๋ณด๋ฅผ ๋ด์ action ๊ฐ์ ์ ๋ฌ๋ฐ์ ์๋ก์ด ์ํ๋ฅผ ๋ฐํํ๋ ํจ์์ด๋ค. useReducer ์์ action ์ ๊ทธ ์ด๋ค ๊ฐ๋ ์ฌ์ฉ ๊ฐ๋ฅํ๋ฉฐ, reducer ํจ์์์ ์๋ก์ด ์ํ๋ฅผ ๋ง๋ค ๋๋ ๋ฐ๋์ ๋ถ๋ณ์ฑ์ ์ง์ผ ์ฃผ์ด์ผ ํ๋ค.
// useReducer ์ฌ์ฉํ๊ธฐ
import { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return { value: state.value + 1 };
case "DECREMENT":
return { value: state.value - 1 };
default:
return state;
}
}
const Counter = () => {
const [state, dispatch] = useReducer(reducer, { value: 0 });
return (
<div>
<p>
ํ์ฌ ์นด์ดํฐ ๊ฐ์ <b>{state.value}</b>์
๋๋ค.
</p>
<button onClick={() => dispatch({ type: "INCREMENT" })}>+1</button>
<button onClick={() => dispatch({ type: "DECREMENT" })}>-1</button>
</div>
);
};
export default Counter;
useReducer ์ ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์๋ reducer ํจ์๋ฅผ ๋ฃ๊ณ , ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์๋ ํด๋น reducer ์ ๊ธฐ๋ณธ๊ฐ {value: 0} ์ ๋ฃ์ด์ค๋ค. ์ด Hook ์ ์ฌ์ฉํ๋ฉด state ๊ฐ๊ณผ dispatch ํจ์๋ฅผ ๋ฐ์ ์จ๋ค. ์ฌ๊ธฐ์ state ๋ ํ์ฌ ๊ฐ๋ฆฌํค๊ณ ์๋ ์ํ๊ณ , dispatch ๋ ์ก์ ์ ๋ฐ์์ํค๋ ํจ์์ด๋ค. dispatch(action) ๊ณผ ๊ฐ์ ํํ๋ก, ํจ์ ์์ ํ๋ผ๋ฏธํฐ๋ก action ๊ฐ์ ๋ฃ์ด์ฃผ๋ฉด reducer ํจ์๊ฐ ํธ์ถ๋๋ ๊ตฌ์กฐ์ด๋ค.
// Info.js
import { useReducer } from "react";
function reducer(state, action) {
return {
...state, // useReducer ๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ state ๊ฐ (name:'', nickname:'') ๋ณต์ฌ
[action.name]: action.value, // action.name ์ e.target.name (input ์ name) ์ด๋ฉฐ action.value ๋ e.target.value (input ์ value) ์ธ ๊ฒ์ด๋ค.
};
}
const Info = () => {
const [state, dispatch] = useReducer(reducer, {
name: "", // reducer ์ ...state ๊ฐ์ผ๋ก ์ ๋ฌํ๊ธฐ
nickname: "",
});
const { name, nickname } = state; // state ๊ฐ ๊ฐ์ง๊ณ ์๋ name, nickname ๊ฐ์ name, nickname ํ๋์ ๋ฃ์ด์ค๋ค.
const onChange = (e) => {
dispatch(e.target); // action ์ e.target
console.log(e.target);
};
return (
<div>
<input name="name" value={name} onChange={onChange} />
<input name="nickname" value={nickname} onChange={onChange} />
<div>์ด๋ฆ : {name}</div>
<div>๋๋ค์ : {nickname}</div>
</div>
);
};
export default Info;
dispatch(e.target) ์ผ๋ก ์ฌ๊ธฐ์ dispatch ๊ฐ ์ ๋ฌํ๋ action ์ e.target ์ด๋ค. ์ฆ, action.name ์ e.target.name ์ด๊ณ ์ด๊ฒ์ input ์์์ name ์์ฑ์ ๋งํ๋ค. action.value ๋ e.target.value ์ด๊ณ ์ด๊ฒ์ input ์์์ value ์์ฑ์ ๋งํ๋ค. ๋ฐ๋ผ์ ์์ input ์์์ name="name" ๋ฐ name="nickname" ์ ๋ช ์ํด์ฃผ์ง ์์ผ๋ฉด input ์ ๊ฐ ์ ๋ ฅ์ด ๋ถ๊ฐํ๊ณ , ์คํ์ด ์ ๋๋ก ๋์ง ์๋๋ค.
์น ์คํ ํ๋ฉด

๐ก useMemo
useMemo ๋ฅผ ์ฌ์ฉํ๋ฉด ํจ์ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ๋ฐ์ํ๋ ์ฐ์ฐ์ ์ต์ ํํ ์ ์๋ค.
// Average.js
import { useState, useMemo } from "react";
const getAverage = (numbers) => {
console.log("ํ๊ท ๊ฐ ๊ณ์ฐ ์ค..");
console.log(numbers);
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
};
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState("");
const onChange = (e) => {
setNumber(e.target.value);
};
const onInsert = () => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber("");
};
// ํน์ ๊ฐ์ด ๋ฐ๋์์ ๋๋ง ์ฐ์ฐ์ ์คํํ๊ณ ์ํ๋ ๊ฐ์ด ๋ฐ๋์ง ์์๋ค๋ฉด ์ด์ ์ ์ฐ์ฐํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ฌ์ฉํ๋ ๋ฐฉ์
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>๋ฑ๋ก</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
{/* list ๋ value ๋ง ๋ด๊ธด ๋ฆฌ์คํธ๋ก ๋จ. */}
<div>
<b>ํ๊ท ๊ฐ: </b> {avg}
</div>
</div>
);
};
export default Average;
const avg = useMemo(() => getAverage(list), [list]);
useMemo ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ๋๋ง ํ๋ ๊ณผ์ ์์ ํน์ ๊ฐ์ด ๋ฐ๋์์ ๋๋ง ์ฐ์ฐ์ ์คํํ๊ณ ์ํ๋ ๊ฐ์ด ๋ฐ๋์ง ์์๋ค๋ฉด ์ด์ ์ ์ฐ์ฐํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ฌ์ฉํ๋ ๋ฐฉ์์ด๋ค. ์์ ์ฝ๋์์๋ list ์ ๊ฐ์ด ๋ฐ๋์์ ๋๋ง ์ฐ์ฐ์ ์คํํ๋๋ก ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ฅผ list ๋ก ๋์ด ๋ ๋๋ง ํ ๋๋ง๋ค ๊ฒ์ฌํ๋๋ก ํ๋ค.
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
list.map ์ผ๋ก ์ธํด value ์ index ์ ๋ฐ๋ผ <li> ํ๊ทธ๋ก ๋ฌถ์ฌ์ง๊ณ list ๋ก ๋ฌถ์ฌ์ ธ ๋์จ๋ค.
๐ก useCallback
// useCallback
import { useState, useMemo, useCallback } from "react";
const getAverage = (numbers) => {
console.log("ํ๊ท ๊ฐ ๊ณ์ฐ ์ค..");
console.log(numbers);
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
};
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState("");
const onChange = useCallback((e) => {
setNumber(e.target.value);
}, []); // ์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ ๋๋ง๋ ๋๋ง ํจ์ ์์ฑ
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber("");
}, [number, list]); // number ํน์ list ๊ฐ ๋ฐ๋์์ ๋๋ง ํจ์ ์์ฑ
// ํน์ ๊ฐ์ด ๋ฐ๋์์ ๋๋ง ์ฐ์ฐ์ ์คํํ๊ณ ์ํ๋ ๊ฐ์ด ๋ฐ๋์ง ์์๋ค๋ฉด ์ด์ ์ ์ฐ์ฐํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ฌ์ฉํ๋ ๋ฐฉ์
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>๋ฑ๋ก</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
{/* list ๋ value ๋ง ๋ด๊ธด ๋ฆฌ์คํธ๋ก ๋จ. */}
<div>
<b>ํ๊ท ๊ฐ: </b> {avg}
</div>
</div>
);
};
export default Average;
useCallback ์ ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์๋ ์์ฑํ๊ณ ์ถ์ ํจ์๋ฅผ ๋ฃ๊ณ , ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์๋ ๋ฐฐ์ด์ ๋ฃ์ผ๋ฉด ๋๋ค. ์ด ๋ฐฐ์ด์๋ ์ด๋ค ๊ฐ์ด ๋ฐ๋์์ ๋ ํจ์๋ฅผ ์๋ก ์์ฑํด์ผ ํ๋์ง ๋ช ์ํด์ผ ํ๋ค. onChange ์ฒ๋ผ ๋น์ด ์๋ ๋ฐฐ์ด์ ๋ฃ๊ฒ ๋๋ฉด ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ๋ ๋ง๋ค์๋ ํจ์๋ฅผ ๊ณ์ํด์ ์ฌ์ฌ์ฉํ๊ฒ ๋๋ฉฐ onInsert ์ฒ๋ผ ๋ฐฐ์ด ์์ number ์ list ๋ฅผ ๋ฃ๊ฒ ๋๋ฉด input ๋ด์ฉ์ด ๋ฐ๋๊ฑฐ๋ ์๋ก์ด ํญ๋ชฉ์ด ์ถ๊ฐ๋ ๋ ์๋ก ๋ง๋ค์ด์ง ํจ์๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค.
๐ก useRef
ํจ์ ์ปดํฌ๋ํธ์์ ref ๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ํด ์ค๋ค.
// useRef
import { useState, useMemo, useCallback, useRef } from "react";
const getAverage = (numbers) => {
console.log("ํ๊ท ๊ฐ ๊ณ์ฐ ์ค..");
console.log(numbers);
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
};
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState("");
const inputEl = useRef(null);
const onChange = useCallback((e) => {
setNumber(e.target.value);
}, []); // ์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ ๋๋ง๋ ๋๋ง ํจ์ ์์ฑ
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber("");
inputEl.current.focus();
}, [number, list]); // number ํน์ list ๊ฐ ๋ฐ๋์์ ๋๋ง ํจ์ ์์ฑ
// ํน์ ๊ฐ์ด ๋ฐ๋์์ ๋๋ง ์ฐ์ฐ์ ์คํํ๊ณ ์ํ๋ ๊ฐ์ด ๋ฐ๋์ง ์์๋ค๋ฉด ์ด์ ์ ์ฐ์ฐํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ฌ์ฉํ๋ ๋ฐฉ์
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} ref={inputEl} />
<button onClick={onInsert}>๋ฑ๋ก</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
{/* list ๋ value ๋ง ๋ด๊ธด ๋ฆฌ์คํธ๋ก ๋จ. */}
<div>
<b>ํ๊ท ๊ฐ: </b> {avg}
</div>
</div>
);
};
export default Average;
inputEl ์ input ์์๋ฅผ ๋งํ๋ค. inputEl.current ๊ฐ์ด ์ค์ input ์์๋ฅผ ๊ฐ๋ฆฌํจ๋ค. ๋ก์ปฌ ๋ณ์๋ ๋ ๋๋ง๊ณผ ์๊ด์์ด ๋ฐ๋ ์ ์๋ ๊ฐ์ ์๋ฏธํ๋ค.
๋์ [๋ฆฌ์กํธ๋ฅผ ๋ค๋ฃจ๋ ๊ธฐ์ ] ์ ์ฐธ๊ณ ํ์ฌ ์์ฑํ ๊ธ์ ๋๋ค.
'JavaScript > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[React] SPA ๋? (0) | 2021.11.08 |
---|---|
[React] ํจ์ ์ปดํฌ๋ํธ์์ ๋ฆฌ๋ ๋๋ง ์ต์ ํ๋ฅผ ์ํ ๋ฐฉ๋ฒ (0) | 2021.10.27 |
[React] ์ปดํฌ๋ํธ ์์๋ณด๊ธฐ (0) | 2021.10.26 |
[React] ๊ธ์ฐ๊ธฐ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ (0) | 2021.10.22 |
[React] Redux ํด๋ ๊ตฌ์กฐ ์ ๋ฆฌํ๊ธฐ (0) | 2021.10.21 |
๋๊ธ