Hook์ React ๋ฒ์ 16.8๋ถํฐ React ์์๋ก ์๋ก ์ถ๊ฐ๋์์ต๋๋ค.
Hook์ ์ด์ฉํ์ฌ ๊ธฐ์กด Class ๋ฐํ์ ์ฝ๋๋ฅผ ์์ฑํ ํ์ ์์ด ์ํ ๊ฐ๊ณผ ์ฌ๋ฌ React์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
hook ๊ธฐ๋ฅ์ ํตํ, life cycle, state ์ ์ด
1.์ปดํฌ๋ํธ ์ฌ์ด์์ ์ํ ๋ก์ง์ ์ฌ์ฌ์ฉํ๊ธฐ ์ด๋ ต๋ค.
๊ธฐ์กด์ ๋ฐฉ๋ฒ: render props, ๊ณ ์ฐจ ์ปดํฌ๋ํธ ํจํด
weak: ์ปดํฌ๋ํธ์ ์ฌ๊ตฌ์ฑ ๊ฐ์, ์ฝ๋ ์ถ์ ์ด๋ ค์
providers, consumers, ๊ณ ์ฐจ ์ปดํฌ๋ํธ render props,
๋ค๋ฅธ ์ถ์ํ์ ๋ํ ๋ ์ด์ด๋ก ๋๋ฌ์ธ์ธ "๋ํผ์ง์ฅ"(wrapper hell)
Hook์ ๋ฐฉ๋ฒ: ์ปดํฌ๋ํธ๋ก๋ถํฐ ์ํ ๊ด๋ จ ๋ก์ง์ ์ถ์ํ ๊ฐ๋ฅ
strength: ๋
๋ฆฝ์ ์ธ ํ
์คํธ์ ์ฌ์ฌ์ฉ์ด ๊ฐ๋ฅ ,
๊ณ์ธต์ ๋ณํ ์์ด ์ํ ๊ด๋ จ ๋ก์ง์ ์ฌ์ฌ์ฉํ ์ ์๊ฒ ํจ.
*๊ณ ์ฐจ ์ปดํฌ๋ํธ(HOC, higher-order component)
:์ปดํฌ๋ํธ ๋ก์ง์ ์ฌ์ฌ์ฉํ๊ธฐ ์ํ React์ ๊ณ ๊ธ ๊ธฐ์
์ปดํฌ๋ํธ๊ฐ UI๋ฅผ props๋ก ๋ณํํ๋ ๋ฐ๋ฉด,
๊ณ ์ฐจ ์ปดํฌ๋ํธ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ค๋ฅธ ์ปดํฌ๋ํธ๋ก ๋ณํํฉ๋๋ค.
*Render Props
:React ์ปดํฌ๋ํธ ๊ฐ์ ์ฝ๋๋ฅผ ๊ณต์ ํ๊ธฐ ์ํด ํจ์ props๋ฅผ ์ด์ฉํ๋ ๊ฐ๋จํ ํ
ํฌ๋
render props ํจํด์ผ๋ก ๊ตฌํ๋ ์ปดํฌ๋ํธ๋ ์์ฒด์ ์ผ๋ก ๋ ๋๋ง ๋ก์ง์ ๊ตฌํํ๋ ๋์ ,
react ์๋ฆฌ๋จผํธ ์์๋ฅผ ๋ฐํํ๊ณ ์ด๋ฅผ ํธ์ถํ๋ ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
<DataProvider render={data => (
<h1>Hello {data.target}</h1>
)}/>
2.๋ณต์กํ ์ปดํฌ๋ํธ๋ค์ ์ดํดํ๊ธฐ ์ด๋ ต๋ค.
๊ด๋ฆฌํ๊ธฐ๊ฐ ํ๋ค์ด์ง๋ ์ํ ๊ด๋ จ ๋ก์ง๋ค๊ณผ ์ฌ์ด๋ ์ดํํธ๊ฐ
์๋ ์ปดํฌ๋ํธ๋ค์ ์ ์ง๋ณด์ํด์ผ ํฉ๋๋ค.
๊ฐ ์๋ช
์ฃผ๊ธฐ ๋ฉ์๋์๋ ์์ฃผ ๊ด๋ จ ์๋ ๋ก์ง์ด ์์ฌ๋ค์ด๊ฐ๊ณ ๋ ํฉ๋๋ค.
ex)
componentDidMount ์ componentDidUpdate๋ ์ปดํฌ๋ํธ์์์
๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์์
์ ์ํํ ๋ ์ฌ์ฉ ๋์ด์ผ ํ์ง๋ง,
๊ฐ์ componentDidMount์์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ค์ ํ๋ ๊ฒ๊ณผ ๊ฐ์
๊ด๊ณ์๋ ๋ก์ง์ด ํฌํจ๋๊ธฐ๋ ํ๋ฉฐ,
componentWillUnmount์์ cleanup ๋ก์ง์ ์ํํ๊ธฐ๋ ํฉ๋๋ค.
weak: ํจ๊ป ๋ณ๊ฒฝ๋๋ ์ํธ ๊ด๋ จ ์ฝ๋๋ ๋ถ๋ฆฌ๋์ง๋ง ์ด์ ์ฐ๊ด ์๋ ์ฝ๋๋ค์
๋จ์ผ ๋ฉ์๋๋ก ๊ฒฐํฉํฉ๋๋ค.
์ด๋ก ์ธํด ๋ฒ๊ทธ๊ฐ ์ฝ๊ฒ ๋ฐ์ํ๊ณ ๋ฌด๊ฒฐ์ฑ์ ๋๋ฌด๋ ์ฝ๊ฒ ํด์นฉ๋๋ค.
Hook์ ํจ์ ์ปดํฌ๋ํธ์์ React state์ ์๋ช ์ฃผ๊ธฐ ๊ธฐ๋ฅ(lifecycle features)์ โ์ฐ๋(hook into)โํ ์ ์๊ฒ ํด์ฃผ๋ ํจ์์ ๋๋ค. Hook์ class ์์์๋ ๋์ํ์ง ์์ต๋๋ค.
๋์ class ์์ด React๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฒ์ ๋๋ค.
import React, { useState } from 'react';
function Example() {
// "count"๋ผ๋ ์ ์ํ ๋ณ์๋ฅผ ์ ์ธํฉ๋๋ค
const [count, setCount] = useState(0);
//useState -> Hook-> state ์ถ๊ฐ
//useState ๊ฐ์ฒด ์๋์ด๋ ๋๋ค
return (
<div>
<p>You clicked {count} times</p>
//setState ๋์ setCount์ฌ์ฉ
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() =>
this.setState({ count: this.state.count + 1 })}>Click me
</button>
</div>
);
}
}
state ๋ณ์ ์ ์ธ
(ํจ์๋ this ๊ฐ์ง์ ์์ -> useState Hook์ ์ง์ ํธ์ถ)
state ๊ฐ์ ธ์ค๊ธฐ
state ๊ฐฑ์ ํ๊ธฐ
(ํจ์๋ setCount์ count ๋ณ์๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฏ๋ก this๋ฅผ ํธ์ถX)
var fruitStateVariable = useState('banana'); // ๋ ๊ฐ์ ์์ดํ
์ด ์๋ ์์ ๋ฐํ
var fruit = fruitStateVariable[0]; // ์ฒซ ๋ฒ์งธ ์์ดํ
var setFruit = fruitStateVariable[1]; // ๋ ๋ฒ์งธ ์์ดํ
useState๋ฅผ ์ด์ฉํ์ฌ ๋ณ์๋ฅผ ์ ์ธํ๋ฉด 2๊ฐ์ ์์ดํ
์์ด ๋ค์ด์๋ ๋ฐฐ์ด๋ก ๋ง๋ค์ด์ง๋๋ค.
์ฒซ ๋ฒ์งธ ์์ดํ
์ ํ์ฌ ๋ณ์๋ฅผ ์๋ฏธํ๊ณ ,
๋ ๋ฒ์งธ ์์ดํ
์ ํด๋น ๋ณ์๋ฅผ ๊ฐฑ์ ํด์ฃผ๋ ํจ์์
๋๋ค
useState ์ฌ์ฉ์ ๊ฐ์ด ๋ค๋ฅธ ๊ฐ์ผ๋ก ์ฌํ ๋น ๋ ํ
๋ฐ const๋ฅผ ์ฐ๋ ์ด์ :
component๊ฐ ๋ค์ rendering ๋๋ฉด ํจ์๊ฐ ๋ค์ ์คํ๋์ด ์ scope๋ฅผ ๋ง๋ค๊ณ
์๋กญ๊ฒ name ๋ณ์๋ฅผ ๋ง๋ค๊ณ , ์ด์ ๋ณ์์๋ ๊ด๋ จ์ด ์์ด์ง๊ฒ ๋์ด const๋ก ์ ์ธํ๋ค.
function ExampleWithManyStates() {
// ์ฌ๋ฌ ๊ฐ์ state๋ฅผ ์ ์ธํ ์ ์์ต๋๋ค!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
function handleOrangeClick() {
// this.setState({ fruit: 'orange' })์ ๊ฐ์ ํจ๊ณผ๋ฅผ ๋
๋๋ค.
setFruit('orange');
}
๐ก Component์ Lifecycle์, component๊ฐ ํ๋์ ๋ ธ๋๋ก DOM์ ์ฌ๋ผ๊ฐ๊ณ , ์์ ๋๊ณ , ๋ด๋ ค์ค๋ ๊ณผ์ ์ผ๋ก ๊ตฌ์ฑ๋๋ค.
๐ ์ฆ, "mounting" (adding nodes to the DOM), "unmounting" (removing them from the DOM), and "updating" (making changes to nodes already in the DOM) ์ผ๋ก ์ด๋ฃจ์ด์ง๋ค.
์ปดํฌ๋ํธ์ ์ธ์คํด์ค๊ฐ ์์ฑ๋์ด DOM ์์ ์ฝ์
๋๋ ๊ฒ.
๋ฆฌ์กํธ์์๋ ์ปดํฌ๋ํธ๋ฅผ ํน์ ์์ญ์ ๋ผ์๋ฃ๋ ํ์๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
์๋ก ReactDOM.render ํจ์๋ฅผ ํตํด์ DOM์ ํน์ ์์ญ์ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ ๋ผ์ ๋ฃ์ ์ ์๊ณ , ์ด๋ฌํ ๊ณผ์ ์ ๋ง์ดํธํ๋ค๊ณ ํํํ๋ค.
< Rendering๊ณผ Mounting >
๐ "Rendering" is any time a function component gets called or a class-based render method gets called which returns a set of instructions for creating DOM.
๐ "Mounting" is when React "renders" the component for the first time and actually builds the initial DOM from those instructions.
๐ ๋ ๋๋ง์ ์ปดํฌ๋ํธ๊ฐ DOM์ ๋ง๋๋ ๋ช
๋ น๋ค์ ๋ฐํํ๋ ํจ์๊ฐ ํธ์ถ๋๋ ๊ฒ์ ๋งํ๊ณ , ๋ง์ดํ
์ ์ปดํฌ๋ํธ๋ฅผ ์ฒ์์ผ๋ก ๋ ๋๋งํ๋ ๊ฒ์ ์๋ฏธํ๋ค.
mount ๋จ๊ณ์ class component lifecycle methods
1. constructor()
2. static getDerivedStateFromProps()
3. render()
4. componentDidMount()
์ด๋ฏธ mount ๋์ด DOM์ ์กด์ฌํ๋ ์ปดํฌ๋ํธ๋ฅผ re-rendering ํ์ฌ ์ ๋ฐ์ดํธ ํ๋ ๊ฒ. (์๋ก mount ํ๋ ๊ฒ ์๋.)
A "re-render" is when React calls the function component again to get a new set of instructions on an already mounted component. Re-renders just update the DOM but don't mount since mounting just happens once.
์ปดํฌ๋ํธ๋ ์๋์ ๋ค ๊ฐ์ง ๊ฒฝ์ฐ์ ์
๋ฐ์ดํธ ๋๋ค.
- props๊ฐ ๋ฐ๋ ๋
- state๊ฐ ๋ฐ๋ ๋
- ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋ ๋
- this.forceUpdate๋ก ๊ฐ์ ๋ก ๋ ๋๋ง์ ํธ๋ฆฌ๊ฑฐํ ๋
update ๋จ๊ณ์ class component lifecycle methods
1. static getDerivedStateFromProps()
2. shouldComponentUpdate()
3. render()
4. getSanphotBeforUpdate()
5. componentDidUpdate()
๋ง์ดํธ์ ๋ฐ๋ ๊ณผ์ . ์ปดํฌ๋ํธ๊ฐ DOM์์ ์ ๊ฑฐ๋๋ ๊ฒ
unmount ๋จ๊ณ์ class component์์๋ componentWillUnmount() method๊ฐ ํธ์ถ๋๋ค.
React ์ปดํฌ๋ํธ ์์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ฑฐ๋ ๊ตฌ๋ ํ๊ณ , DOM์ ์ง์ ์กฐ์ํ๋ ์์
ํน์ง: ๋ค๋ฅธ ์ปดํฌ๋ํธ์ ์ํฅ์ ์ค ์๋ ์๊ณ , ๋ ๋๋ง ๊ณผ์ ์์๋ ๊ตฌํํ ์ ์๋ ์์
Effect Hook, ์ฆ useEffect๋ ํจ์ ์ปดํฌ๋ํธ ๋ด์์ ์ด๋ฐ side effects๋ฅผ ์ํํ ์ ์๊ฒ ํด์ค๋๋ค
main effect๋ render์ return()๋ถ๋ถ์ด๋ผ๊ณ ์๊ฐํ ์ ์๋ค.
useEffect =ใ componentDidMount ใใใใใใ+componentDidUpdate ใใใใใใ+componentWillUnmount
๋ง์ฝ useEffect ์์ ์ค์ ํ ํจ์๊ฐ ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ๊ฐ์ฅ ์ฒ์ ๋ ๋๋ง ๋ ๋๋ง ์คํ๋๊ณ ์ ๋ฐ์ดํธ ํ ๊ฒฝ์ฐ์๋ ์คํ ํ ํ์๊ฐ ์๋ ๊ฒฝ์ฐ์ ํจ์์ ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ๋น์ด์๋ ๋ฐฐ์ด์ ๋ฃ์ด์ฃผ์๋ฉด ๋ฉ๋๋ค.
useEffect(() => {
console.log('๋ง์ดํธ ๋ ๋๋ง ์คํ๋ฉ๋๋ค.');
}, []);
ํด๋์ค ์ปดํฌ๋ํธ์ ๊ฒฝ์ฐ prevProps์ ๊ฐ์ ๊ฐ์ ธ์ ๋น๊ต๋ฅผ ํ์ฌ ๋ก์ง์ํ
componentDidUpdate(prevProps, prevState) {
if (prevProps.value !== this.props.value) {
doSomething();
}
}
useEffect์์๋ ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋๋ ๋ฐฐ์ด ์์ ๊ฒ์ฌ(์ ๋ฐ์ดํธ๋๋์ง)ํ๊ณ ์ถ์ ๊ฐ์ ๋ฃ์ด์ฃผ์๋ฉด ๋๋ต๋๋ค.
useEffect(() => {
console.log(name);
}, [name]); //name์ ์
๋ฐ์ดํธ๊ฐ ์์๊ฒฝ์ฐ render
๋ง์ฝ ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋๊ธฐ ์ ์ด๋, ์ ๋ฐ์ดํธ ๋๊ธฐ ์ง์ ์ ์ด๋ ํ ์์ ์ ์ํํ๊ณ ์ถ๋ค๋ฉด useEffect ์์ ๋ท์ ๋ฆฌ(cleanup) ํจ์๋ฅผ ๋ฐํํด์ฃผ์ด์ผ ํฉ๋๋ค.
useEffect(() => {
console.log('effect');
console.log(name);
return () => {
console.log('cleanup');
console.log(name);
};
});
๋ง์ฝ์, ์ค์ง ์ธ๋ง์ดํธ ๋ ๋๋ง ๋ท์ ๋ฆฌ ํจ์๋ฅผ ํธ์ถํ๊ณ ์ถ์ผ์๋ค๋ฉด useEffect ํจ์์ ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ์ ๋น์ด์๋ ๋ฐฐ์ด์ ๋ฃ์ผ์๋ฉด ๋ฉ๋๋ค.
useEffect(() => {
console.log('effect');
console.log(name);
return () => {
console.log('cleanup');
console.log(name);
};
}, []);
function FriendStatusWithCounter(props) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
});
// ...
}
๋ฐ๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ ํน์ ์ค์ฒฉ๋ ํจ์ ๋ด์์ Hook์ ํธ์ถ โ
Why?
๊ท์น์ ๋ฐ๋ฅด๋ฉด ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ๋๋ง๋ค ํญ์ ๋์ผํ ์์๋ก Hook์ด ํธ์ถ๋๋ ๊ฒ์ด ๋ณด์ฅ
๋ชจ๋ ๋ ๋๋ง์์ Hook์ ํธ์ถ ์์๋ ๊ฐ๊ธฐ ๋๋ฌธ์ ์์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ ์ ์์ต๋๋ค.
function Form() {
// 1. name์ด๋ผ๋ state ๋ณ์๋ฅผ ์ฌ์ฉํ์ธ์.
const [name, setName] = useState('Mary');
// 2. Effect๋ฅผ ์ฌ์ฉํด ํผ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ์ธ์.
useEffect(function persistForm() {
localStorage.setItem('formData', name);
});
// 3. surname์ด๋ผ๋ state ๋ณ์๋ฅผ ์ฌ์ฉํ์ธ์.
const [surname, setSurname] = useState('Poppins');
// 4. Effect๋ฅผ ์ฌ์ฉํด์ ์ ๋ชฉ์ ์
๋ฐ์ดํธํฉ๋๋ค.
useEffect(function updateTitle() {
document.title = name + ' ' + surname;
});
// ...
}
// ------------
// ์ฒซ ๋ฒ์งธ ๋ ๋๋ง
// ------------
useState('Mary') // 1. 'Mary'๋ผ๋ name state ๋ณ์๋ฅผ ์ ์ธํฉ๋๋ค.
useEffect(persistForm) // 2. ํผ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ effect๋ฅผ ์ถ๊ฐํฉ๋๋ค.
useState('Poppins') // 3. 'Poppins'๋ผ๋ surname state ๋ณ์๋ฅผ ์ ์ธํฉ๋๋ค.
useEffect(updateTitle) // 4. ์ ๋ชฉ์ ์
๋ฐ์ดํธํ๊ธฐ ์ํ effect๋ฅผ ์ถ๊ฐํฉ๋๋ค.
// -------------
// ๋ ๋ฒ์งธ ๋ ๋๋ง
// -------------
useState('Mary') // 1. name state ๋ณ์๋ฅผ ์ฝ์ต๋๋ค.(์ธ์๋ ๋ฌด์๋ฉ๋๋ค)
useEffect(persistForm) // 2. ํผ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ effect๊ฐ ๋์ฒด๋ฉ๋๋ค.
useState('Poppins') // 3. surname state ๋ณ์๋ฅผ ์ฝ์ต๋๋ค.(์ธ์๋ ๋ฌด์๋ฉ๋๋ค)
useEffect(updateTitle) // 4. ์ ๋ชฉ์ ์
๋ฐ์ดํธํ๊ธฐ ์ํ effect๊ฐ ๋์ฒด๋ฉ๋๋ค.
// ...
์กฐ๊ฑด๋ฌธ์ Hook์ ์ด๋ค๋ฉด?(2๋ฒ ํญ๋ชฉ)
function Form() {
// 1. name์ด๋ผ๋ state ๋ณ์๋ฅผ ์ฌ์ฉํ์ธ์.
const [name, setName] = useState('Mary');
// 2. Effect๋ฅผ ์ฌ์ฉํด ํผ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ์ธ์.
if (name !== '') {
useEffect(function persistForm() {
localStorage.setItem('formData', name);
});
}
// 3. surname์ด๋ผ๋ state ๋ณ์๋ฅผ ์ฌ์ฉํ์ธ์.
const [surname, setSurname] = useState('Poppins');
// 4. Effect๋ฅผ ์ฌ์ฉํด์ ์ ๋ชฉ์ ์
๋ฐ์ดํธํฉ๋๋ค.
useEffect(function updateTitle() {
document.title = name + ' ' + surname;
});
// ...
}
useState('Mary') // 1. name state ๋ณ์๋ฅผ ์ฝ์ต๋๋ค. (์ธ์๋ ๋ฌด์๋ฉ๋๋ค)
// useEffect(persistForm) // ๐ด Hook์ ๊ฑด๋๋ฐ์์ต๋๋ค!
useState('Poppins') // ๐ด 2 (3์ด์๋). surname state ๋ณ์๋ฅผ ์ฝ๋ ๋ฐ ์คํจํ์ต๋๋ค.
useEffect(updateTitle) // ๐ด 3 (4์๋). ์ ๋ชฉ์ ์
๋ฐ์ดํธํ๊ธฐ ์ํ effect๊ฐ ๋์ฒด๋๋ ๋ฐ ์คํจํ์ต๋๋ค.
name !== '' ์กฐ๊ฑด
์ฒซ ๋ฒ์งธ ๋ ๋๋ง =>true
๊ทธ๋ค์ ๋ ๋๋ง์์ ํผ์ ์ด๊ธฐํ๋จ => false
Hook์ ์์๊ฐ ํ๋์ฉ ๋ฐ๋ฆฌ๋ ๋ฒ๊ทธ ๋ฐ์
ํด๊ฒฐ๋ฐฉ๋ฒ
useEffect(function persistForm() {
// ๐ ๋ ์ด์ ์ฒซ ๋ฒ์งธ ๊ท์น์ ์ด๊ธฐ์ง ์์ต๋๋ค
if (name !== '') {
localStorage.setItem('formData', name);
}
});
Hook์ ์ผ๋ฐ์ ์ธ JavaScript ํจ์์์ ํธ์ถ โ
Why?
์ด ๊ท์น์ ์งํค๋ฉด ์ปดํฌ๋ํธ์ ๋ชจ๋ ์ํ ๊ด๋ จ ๋ก์ง์ ์์ค์ฝ๋์์ ๋ช
ํํ๊ฒ ๋ณด์ด๋๋ก ๊ฐ๋ฅ
์์ ๋ง์ Hook์ ๋ง๋ค๋ฉด ์ปดํฌ๋ํธ ๋ก์ง์ ํจ์๋ก ๋ฝ์๋ด์ด ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ฐ์ ์ฌ์ง์์ ๋ ํจ์ ์ปดํฌ๋ํธ์ ๊ฐ์ ๋ก์ง ์ฌ์ฉ์ ์ ์ ์์ต๋๋ค.
๋ ๊ฐ์ ์๋ฐ์คํฌ๋ฆฝํธ ํจ์์์ ๊ฐ์ ๋ก์ง์ ๊ณต์ ํ๊ณ ์ ํ ๋๋ ๋ ๋ค๋ฅธ ํจ์๋ก ๋ถ๋ฆฌํฉ๋๋ค. ์ปดํฌ๋ํธ์ Hook ๋ํ ํจ์์ด๊ธฐ ๋๋ฌธ์ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ต๋๋ค!
์ฌ์ฉ์ ์ ์ Hook์ ์ด๋ฆ์ด use๋ก ์์ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ํจ์
import { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// friendID๋ฅผ ์ธ์๋ก ๋ฐ๊ณ ์จ๋ผ์ธ ์ํ์ ์ฌ๋ถ๋ฅผ ๋ฐํ
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
๊ณตํต๋ถ๋ถ์ useFriendStatus() ๋ฅผ ์ด์ฉํ์ฌ ๊ฐ๋จํ๊ฒ ์ฒ๋ฆฌํ๋ค.
์ด๋ ์ฃผ์์ฌํญ๋ค์
1. ์ฌ์ฉ์ ์ ์ Hook์ ์ด๋ฆ์ โuseโ๋ก ์์๋์ด์ผ ํ๋ค
Why?
ํน์ ํ ํจ์๊ฐ ๊ทธ ์์์ Hook์ ํธ์ถํ๋์ง๋ฅผ ์ ์ ์๊ธฐ ๋๋ฌธ์ use ์ฌ์ฉ ์ํ ์, Hook ๊ท์น์ ์๋ฐ ์ฌ๋ถ๋ฅผ ์๋์ผ๋ก ์ฒดํฌํ ์ ์์ต๋๋ค.
2. ๊ฐ์ Hook์ ์ฌ์ฉํ๋ ๋ ๊ฐ์ ์ปดํฌ๋ํธ๋ state๋ฅผ ๊ณต์ โ
Why?
์ํ ๊ด๋ จ ๋ก์ง์ ์ฌ์ฌ์ฉํ๋ ๋ฉ์ปค๋์ฆ์ด์ง๋ง ์ฌ์ฉ์ Hook์ ์ฌ์ฉํ ๋๋ง๋ค ๊ทธ ์์ state์ effect๋ ์์ ํ ๋ ๋ฆฝ์ ์ด๋ค.
Q1:Class๋ก ํ์ง ๋ชปํ๋ ๊ฒ ์ค์ Hook์ผ๋ก ๊ฐ๋ฅํ ๊ฒ์ด ๋ฌด์์ธ๊ฐ?
A1:Hook์ ์ปดํฌ๋ํธ ๊ฐ์ ๊ธฐ๋ฅ์ ์ฌ์ฌ์ฉํ ์ ์๋ ๊ฐ๋ ฅํ๊ณ ํํ์ ์ธ ์๋ก์ด ๋ฐฉ๋ฒ์ ์ ๊ณต(์์ ๋ง์ Hook ๋ง๋ค๊ธฐ)
Q2.์๋ช ์ฃผ๊ธฐ ๋ฉ์๋๊ฐ Hook์ ์ด๋ป๊ฒ ๋์ํฉ๋๊น?
A2:
- constructor: useState ํธ์ถ์์ state๋ฅผ ์ด๊ธฐํ ํ ์ ์์ต๋๋ค.
์ด๊ธฐ state๋ฅผ ๊ณ์ฐํ๋ ๊ฒ์ด ๋น์ธ๋ฉด useState์ ํจ์ ์ปดํฌ๋ํธ๋ฅผ ์ ๋ฌํ ์ ์์ต๋๋ค.const [state, setState] = useState(() => { const initialState = someExpensiveComputation(props); return initialState; });
- getDerivedStateFromProps: ๋์ ๋ ๋๋งํ๋ ๋์ ์ ๋ฐ์ดํธ ์์ฝ.
- shouldComponentUpdate: React.memo๋ฅผ ์ฐธ์กฐํด์ฃผ์ธ์.
- render: ์ด๊ฒ์ ํจ์ ์ปดํฌ๋ํธ ๋ณธ์ฒด ์์ฒด์ ๋๋ค.
- componentDidMount, componentDidUpdate, componentWillUnmount:
useEffect Hook์ ์ด๋ค์ ๋ชจ๋ ์กฐํฉ์ ํํํ ์ ์์ต๋๋ค.- getSnapshotBeforeUpdate, componentDidCatch ๊ทธ๋ฆฌ๊ณ getDerivedStateFromError: ์ด๋ฌํ ๋ฉ์๋์ ๋ํ Hook์ ์์ง๋ง, ๊ณง ์ถ๊ฐ๋ ์์ ์ ๋๋ค.
Q3.ํ๋ ๋๋ ์ฌ๋ฌ state ๋ณ์๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๊น?
A3: useState()๋ฅผ ํ ๋ฒ๋ง ํธ์ถํ๊ณ ๋ชจ๋ state๋ฅผ ๋จ์ผ ๊ฐ์ฒด์ ๋ฃ๊ณ ์ถ์ ์ ์์ต๋๋ค.function Box() { const [state, setState] = useState({ left: 0, top: 0, width: 100, height: 100 }); // ... } -------------------------------------------------------------- // ... useEffect(() => { function handleWindowMouseMove(e) { // "... state"๋ฅผ spread ํ์ฌ ๋๋น์ ๋์ด๊ฐ "์์ค"๋์ง ์์ต๋๋ค setState(state => ({ ...state, left: e.pageX, top: e.pageY })); } // ์ฃผ์: ์ด ๊ตฌํ์ ์ฝ๊ฐ ๋จ์ํ๋์์ต๋๋ค window.addEventListener('mousemove', handleWindowMouseMove); return () => window.removeEventListener('mousemove', handleWindowMouseMove); }, []); // ...