1. React์ Hooks
Wanted Frontend Challenge - React ๊ฐ์ ๋ด์ฉ ์ ๋ฆฌ_2-1
React์ Hooks : useState, useContext, useEffect
Hook์ ์ฅ์
Hook ์ฌ์ฉ ์ ๊ท์น
Counter
์ปดํฌ๋ํธ ํธ์ถ0
์ ์ ๋ฌํ๋ฉฐ useState ํธ์ถhandleClick
ํจ์๊ฐ ์คํ๋๋ฉฐ ์ํ๋ณ๊ฒฝ ํจ์(setCount
) ํธ์ถCounter
์ปดํฌ๋ํธ ๋ ๋ฒ์งธ ์คํsetCount
)๋ก ์ธํด count
๊ฐ์ด 1
์ด ๋์๊ธฐ ๋๋ฌธ์ ์ด๊ธฐ๊ฐ(0
) ํ ๋น๋ฌธ ๋ฌด์useContext๋ Context API๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ญ ์ํ๋ฅผ ์ปดํฌ๋ํธ ๋ด์์ ์์ฝ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ React์ Hook
Context API๋ React์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ญ์ผ๋ก ๊ณต์ ํ๊ธฐ ์ํด ์ฌ์ฉํ๋ฉฐ, ์ฃผ๋ก props drilling ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฌ์ฉ
Context API์์ state ๊ฐ์ ๋ณ๊ฒฝํ๋ฉด, Provider๋ก ๊ฐ์ผ ๋ชจ๋ ์ปดํฌ๋ํธ๋ค์ด ๋ฆฌ๋ ๋๋ง
ex. ํ ๋ง ๋ฐ์ดํฐ(๋คํฌ, ๋ผ์ดํธ) / ์ธ์ฆ ๋ ์ฌ์ฉ์ ํ์ธ(๋ก๊ทธ์ธ) / ์ด ์ธ์ ์์ฃผ ์ ๋ฐ์ดํธํ ํ์๊ฐ ์๋ ๋ฐ์ดํฐ
Prop drilling์ React ์ ํ๋ฆฌ์ผ์ด์
์์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ธฐ ์ํด ํ์ํ ๊ณผ์ ์ ์ค๋ช
ํ๋ ์ฉ์ด.
React์์๋ ์์ ์ปดํฌ๋ํธ์์ ๋ฐ์ดํฐ(์ํ)๋ฅผ ํ์ ์ปดํฌ๋ํธ๋ก ์ ๋ฌํ๊ธฐ ์ํด ์ค๊ฐ ์ปดํฌ๋ํธ๋ฅผ ํตํด ํ๋กํผํฐ๋ฅผ ๋ด๋ ค์ฃผ๊ฒ ๋๋ค.
์ค๊ฐ ์ปดํฌ๋ํธ ์
์ฅ์์๋ ํ๊ฒ์ธ ์์ ์ปดํฌ๋ํธ์๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํด์ฃผ๊ธฐ ์ํด ์ฌ์ฉํ์ง ์๋ ํ๋กํผํฐ๋ฅผ ๋ฐ๋ ์
์ด๋ค.
๋ง์ฝ 10๊ฐ, 20๊ฐ์ ์ปดํฌ๋ํธ๋ฅผ ๊ฑฐ์ณ์ผํ๋ค๋ฉด?
-> ๊ฐ์ฅ ๋จผ์ Props๊ฐ ์ด๋์ ์จ๊ฒ์ธ์ง ์ถ์ ์ด ์ด๋ ค์ -> ์ ์ง๋ณด์ ๋นํจ์จ
์ฌ์ฉ ๋ฐฉ๋ฒ
createContext๋ก context ์์ฑ
๋์ ์ปดํฌ๋ํธ(<Form />
)์ ๊ฐ์ ๋ด๋ ค์ฃผ๊ธฐ ์ํด์ Provider๋ก
๋์ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ผ๋ค. -> Provider ํ์ ์ปดํฌ๋ํธ์์ ๋ชจ๋ ์ ๊ทผ ๊ฐ๋ฅ
Provider์ value ์์ฑ์ผ๋ก ๋ฐ์ดํฐ ์ ๋ฌ
import { createContext, useContext } from 'react';
const ThemeContext = createContext(null);
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
)
}
ํ์ ์ปดํฌ๋ํธ์์ useContext๋ฅผ ์ด์ฉํด context์ value(dark
)์ ์ ๊ทผ ๊ฐ๋ฅ
const theme = useContext(ThemeContext)
์์ ๋ณ์๋ฅผ className์ผ๋ก ํ์ฉํ์ฌ CSS ๋ณ๊ฒฝ
const className = 'panel-' + theme
function Form() {
return (
<Panel title="Welcome">
<Button>Sign up</Button>
<Button>Log in</Button>
</Panel>
);
}
function Panel({ title, children }) {
const theme = useContext(ThemeContext);
const className = 'panel-' + theme;
return (
<section className={className}>
<h1>{title}</h1>
{children}
</section>
)
}
function Button({ children }) {
const theme = useContext(ThemeContext);
const className = 'button-' + theme;
return (
<button className={className}>
{children}
</button>
);
}
๊ด๋ จ CSS ์์
.panel-light {
background-color: #f4f4f4;
color: #333;
}
.panel-dark {
background-color: #222;
color: #fff;
}
.button-light {
background-color: #fff;
color: #333;
border: 1px solid #333;
}
.button-dark {
background-color: #333;
color: #fff;
border: 1px solid #fff;
}
light / dark
)๊ฐ ๋ณ๊ฒฝ๋๋ฉด Provider์ ํ์ ์ปดํฌ๋ํธ๋ค์ด ๋ชจ๋ ๋ฆฌ๋ ๋๋ง๋๋ฉฐ css๊ฐ ๋ณ๊ฒฝ ๋๋ค.useEffect๋ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ๋๋ง๋ค ํน์ ์์
์ ์ํํ ์ ์๋๋ก ํ๋ React์ Hook
useEffect(callback[, dependencies])
์ปดํฌ๋ํธ์ ์๋ช
์ฃผ๊ธฐ
mount
update
unmout
import React, { useEffect } from 'react';
function TimerComponent() {
useEffect(() => {
const timerId = setInterval(() => {
console.log('Timer tick');
}, 1000);
return () => {
clearInterval(timerId); // ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋ ๋ ํ์ด๋จธ๋ฅผ ์ข
๋ฃ
};
}, []); // ์์กด์ฑ ๋ฐฐ์ด์ด ๋น ๋ฐฐ์ด์ด๋ฏ๋ก ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ๋ ๋ ํ ๋ฒ๋ง ์คํ
return (
<div>
Timer Component
</div>
);
}
export default TimerComponent;
mount์ rendering์ ์ฐจ์ด
Props Drilling์ ๊ฐ๋ ๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ