React Hooks ํบ์๋ณด๊ธฐ!๐ช
React Hooks๋ 2018๋ ์ ๋์ ๋ ๊ธฐ๋ฅ์ผ๋ก, ํจ์ํ ์ปดํฌ๋ํธ์์ ์ํ์ ๋ผ์ดํ์ฌ์ดํด์ ๋ค๋ฃฐ ์ ์๊ฒ ํด์ฃผ๋ ๋๊ตฌ์ ๋๋ค. Hooks๋ React ๊ฐ๋ฐ ๋ฐฉ์์ ํ์ ์ ์ผ๋ก ๋ณํ์์ผฐ์ผ๋ฉฐ, ์ค๋๋ ํจ์ํ ์ปดํฌ๋ํธ๊ฐ ํด๋์คํ ์ปดํฌ๋ํธ๋ฅผ ๋์ฒดํ๊ฒ ๋ ํต์ฌ ์ด์ ์ ๋๋ค.
์ด๋ฒ ๊ธ์์๋ Hooks์ ๊ฐ๋ ๋ถํฐ, ์ฃผ์ Hooks์ ํ์ฉ๋ฒ, ์ฃผ์์ฌํญ๊น์ง ํญ๋๊ฒ ๋ค๋ค๋ณผ๊ฒ์!
Hooks๋ ๋ฌด์์ธ๊ฐ? ๐ค
Hooks๋ React ํจ์ํ ์ปดํฌ๋ํธ์์ ์ํ ๊ด๋ฆฌ ๋ฐ ๋ผ์ดํ์ฌ์ดํด ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๊ธฐ๋ฅ์ ๋๋ค.
Hooks์ ํ์ ๋ฐฐ๊ฒฝ
- ์ฝ๋ ๊ฐ๋ ์ฑ: ํด๋์คํ ์ปดํฌ๋ํธ๋ ๋ณต์กํ ๋ก์ง์ผ๋ก ์ธํด ์ฝ๋๊ฐ ๊ธธ๊ณ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์ต๋๋ค.
- ์ฌ์ฌ์ฉ์ฑ ๋ถ์กฑ: ํด๋์คํ ์ปดํฌ๋ํธ์์๋ ๋น์ทํ ๋ก์ง์ ์ฌ์ฌ์ฉํ๊ธฐ ์ด๋ ต๊ณ , HOC๋ Render Props ๊ฐ์ ๋ณต์กํ ํจํด์ด ํ์ํ์ต๋๋ค.
- ํจ์ํ ์ปดํฌ๋ํธ์ ํ๊ณ: Hooks ์ด์ ์๋ ํจ์ํ ์ปดํฌ๋ํธ์์ ์ํ๋ ๋ผ์ดํ์ฌ์ดํด ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์์ต๋๋ค.
Hooks์ ํน์ง
- ์์ ํ ํจ์ํ ์ปดํฌ๋ํธ ์ง์: ํด๋์คํ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ ํ์ ์์ด ๋ชจ๋ ๊ธฐ๋ฅ์ ํจ์ํ ์ปดํฌ๋ํธ์์ ๊ตฌํํ ์ ์์
- ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ ์ฆ๊ฐ: ์ปค์คํ Hooks๋ฅผ ์ฌ์ฉํ๋ฉด ๋ก์ง์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ์ถ์ถ ๊ฐ๋ฅ
- ์ ์ง์ ๋์ : ๊ธฐ์กด ์ฝ๋๋ฅผ ์์ ํ ๋ฆฌํฉํ ๋งํ ํ์ ์์ด ํ์ํ ๋ถ๋ถ์๋ง ๋์ ๊ฐ๋ฅ
- React 16.8 ์ด์์์ ์ฌ์ฉ ๊ฐ๋ฅ: Hooks๋ React 16.8 ๋ฒ์ ๋ถํฐ ์ง์
์ฃผ์ Hooks ๐๏ธ
1. useState
- ์ญํ : ์ํ ๊ด๋ฆฌ
- ์ฌ์ฉ๋ฒ:
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
- ์ฅ์ :
- ๊ฐ๊ฒฐํ ์ํ ๊ด๋ฆฌ
- ํด๋์คํ ์ปดํฌ๋ํธ์ this.state์ this.setState ๋์ฒด
2. useEffect
- ์ญํ : ์ปดํฌ๋ํธ์ ๋ผ์ดํ์ฌ์ดํด ๊ด๋ฆฌ (componentDidMount, componentDidUpdate, componentWillUnmount ๋์ฒด)
- ์ฌ์ฉ๋ฒ:
import React, { useState, useEffect } from "react";
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
return () => clearInterval(interval); // Cleanup
}, []); // ๋น ๋ฐฐ์ด๋ก ์ฒซ ๋ ๋๋ง ์ 1ํ ์คํ
return <p>Seconds: {seconds}</p>;
}
- ํน์ง:
- ์์กด์ฑ ๋ฐฐ์ด: ์ด๋ค ์ํ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง ์คํํ ์ง ์ ์
- Cleanup: ๋ฐํ๊ฐ์ผ๋ก ์ ๋ฆฌ(clean-up) ๋ก์ง์ ์์ฑ
3. useContext
- ์ญํ : Context API๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋๋ค.
- ์ฌ์ฉ๋ฒ:
import React, { createContext, useContext } from "react";
const ThemeContext = createContext("light");
function ThemedComponent() {
const theme = useContext(ThemeContext);
return <p>Current theme: {theme}</p>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedComponent />
</ThemeContext.Provider>
);
}
- ์ฅ์ :
- ๋ณต์กํ Consumer ์ปดํฌ๋ํธ ํธ๋ฆฌ ์์ด Context ๊ฐ์ ์ ๊ทผ ๊ฐ๋ฅ
- ์ฝ๋ ๊ฐ๋ ์ฑ ํฅ์
4. useRef
- ์ญํ : DOM ์์ ๋๋ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ ์ฐธ์กฐ
- ์ฌ์ฉ๋ฒ:
import React, { useRef } from "react";
function TextInputFocus() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
- ํน์ง:
- useRef๋ ์ํ์ ๋ฌ๋ฆฌ ๊ฐ์ด ๋ณ๊ฒฝ๋์ด๋ ๋ฆฌ๋ ๋๋ง์ ๋ฐ์์ํค์ง ์์
5. useReducer
- ์ญํ : ๋ณต์กํ ์ํ ๊ด๋ฆฌ๋ฅผ ์ํ ๋์ฒด ์ต์ (useState ๋์ฒด)
- ์ฌ์ฉ๋ฒ:
import React, { useReducer } from "react";
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
}
- ์ฅ์ :
- ์ํ ์ ๋ฐ์ดํธ ๋ก์ง์ ์ปดํฌ๋ํธ ์ธ๋ถ๋ก ๋ถ๋ฆฌ ๊ฐ๋ฅ
- ์ํ ์ ๋ฐ์ดํธ๊ฐ ๋ณต์กํ ๊ฒฝ์ฐ ์ ํฉ
6. useMemo & useCallback
- ์ญํ : ๋ถํ์ํ ์ฐ์ฐ ๋ฐ ํจ์ ์ฌ์์ฑ์ ๋ฐฉ์งํ์ฌ ์ฑ๋ฅ ์ต์ ํ
- ์ฌ์ฉ๋ฒ:
import React, { useState, useMemo, useCallback } from "react";
function ExpensiveComponent({ compute, number }) {
console.log("Rendering...");
return <p>Result: {compute(number)}</p>;
}
function App() {
const [count, setCount] = useState(0);
const [value, setValue] = useState(10);
const compute = useCallback((number) => number * 2, []);
const expensiveValue = useMemo(() => value * 100, [value]);
return (
<div>
<ExpensiveComponent compute={compute} number={value} />
<p>Expensive Value: {expensiveValue}</p>
<button onClick={() => setCount(count + 1)}>Re-render</button>
</div>
);
}
- ํน์ง:
- useMemo: ๊ฐ์ ์บ์ฑ
- useCallback: ํจ์์ ์ฌ์์ฑ ๋ฐฉ์ง
Hooks ์ฌ์ฉ ์ ์ฃผ์์ฌํญโ ๏ธ
- Hooks๋ ์ต์์์์๋ง ํธ์ถ
- ์กฐ๊ฑด๋ฌธ, ๋ฐ๋ณต๋ฌธ, ์ค์ฒฉ๋ ํจ์ ๋ด์์ ํธ์ถํ๋ฉด ์ ๋ฉ๋๋ค.
- React๊ฐ Hooks ํธ์ถ ์์๋ฅผ ๋ณด์ฅํ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
- React ํจ์ํ ์ปดํฌ๋ํธ ๋ด์์๋ง ์ฌ์ฉ
- ํด๋์คํ ์ปดํฌ๋ํธ ๋๋ ์ผ๋ฐ ํจ์์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์์กด์ฑ ๋ฐฐ์ด ๊ด๋ฆฌ
- useEffect๋ useMemo์์ ์์กด์ฑ ๋ฐฐ์ด์ ์๋ชป ์ค์ ํ๋ฉด ์์์น ๋ชปํ ๋์์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
Hooks๋ก ์์ฑํ ์ค๋ฌด ์์ ๐ผ
React ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ค์์ Hooks๋ฅผ ์กฐํฉํด ์ฌ์ฉํ๋ฉด ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์์ต๋๋ค.
์์ : ํ ์ผ ๊ด๋ฆฌ ์ฑ
import React, { useState, useReducer, useRef } from "react";
function reducer(todos, action) {
switch (action.type) {
case "add":
return [...todos, { id: Date.now(), text: action.payload, done: false }];
case "toggle":
return todos.map((todo) =>
todo.id === action.payload ? { ...todo, done: !todo.done } : todo
);
case "delete":
return todos.filter((todo) => todo.id !== action.payload);
default:
return todos;
}
}
function TodoApp() {
const [todos, dispatch] = useReducer(reducer, []);
const [text, setText] = useState("");
const inputRef = useRef();
const addTodo = () => {
if (text.trim()) {
dispatch({ type: "add", payload: text });
setText("");
inputRef.current.focus();
}
};
return (
<div>
<input
ref={inputRef}
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Add a task"
/>
<button onClick={addTodo}>Add</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<span
style={{ textDecoration: todo.done ? "line-through" : "none" }}
onClick={() => dispatch({ type: "toggle", payload: todo.id })}
>
{todo.text}
</span>
<button onClick={() => dispatch({ type: "delete", payload: todo.id })}>
Delete
</button>
</li>
))}
</ul>
</div>
);
}
export default TodoApp;
Hooks์ ์ฅ์ ์์ฝ ๐๏ธ
- ์ฝ๋ ๊ฐ๊ฒฐ์ฑ
- ๋ก์ง ์ฌ์ฌ์ฉ์ฑ ์ฆ๊ฐ
- ํด๋์คํ ์ปดํฌ๋ํธ์ ๋ณต์กํ ํจํด ์ ๊ฑฐ
- ์ํ ๊ด๋ฆฌ ๋ฐ ์ฑ๋ฅ ์ต์ ํ
๐ท์ ์ค์ ๊ฐ๋ฐ์๊ฐ ๋์ด๋ด ์๋น! ๐ท
'Front-end > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[React] useEffect: ๋ผ์ดํ ์ฌ์ดํด ๊ด๋ฆฌ์ ๐ฎ (2) | 2024.12.09 |
---|---|
[React] useMemo: ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ๋น์ฅ์ ๋ฌด๊ธฐ ๐ก๏ธ (1) | 2024.12.08 |
[React] render() ํจ์ ์๋ฒฝ ๊ฐ์ด๋ โจ (0) | 2024.12.06 |
[React] React.StrictMode: ๊น์ด ์๊ณ ์์ฐฌ ์๋ฒฝ ๊ฐ์ด๋ ๐ (1) | 2024.12.05 |
React์ ref: DOM๊ณผ์ ์ํต์ ์ํ ๋น๋ฐ ํต๋ก โจ (1) | 2024.11.29 |