๐ ์ ๋ฌผ ๋ญํน๊ณผ ํํฐ๋ง
ํํฐ๋ง ๊ธฐ๋ฅ ๊ตฌํ์ ๋ฐ์ํ ๋ฌธ์ ์
โ ํ์ฌ๊น์ง ๋ด๊ฐ ์ง ํด๋ ๊ตฌ์กฐ๋ค.
๐ฆsection
โฃ ๐Ranking
โ โฃ ๐Categories
โ โ โฃ ๐GiftCategories.tsx
โ โ โ ๐WhoCategories.tsx
โ โฃ ๐RankingItems.tsx
โ โ ๐RankingSection.tsx
RankingSection์ ๊ฐ์ฅ ์์ ์ปดํฌ๋ํธ๋ก ์ง์ ํ๊ณ ์นดํ ๊ณ ๋ฆฌ์ ์ํ ๋ชฉ๋ก์ ๋ณด์ฌ์ฃผ๋ ๋ถ๋ถ์ ๋ถ๋ฆฌํด์ ์ปดํฌ๋ํธํ ํ ๋ค์, RankingSection์ import ํด์ฃผ๋ ๋ฐฉ์์ผ๋ก ์์ฑํ๋ค.
<ContentWrapper>
<WhoCategories />
<Space />
<GiftCategories />
<RankingItems />
</ContentWrapper>
์ฝ๋์ ๊ฐ๋ ์ฑ์ ์ํด ์ฑํํ ๋ฐฉ๋ฒ์ด์์ผ๋, categories์์ ์ ํํ ๊ฐ์ผ๋ก ํํฐ๋ง ๊ธฐ๋ฅ์ ๊ตฌํํ์ง ๋ชปํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ๐
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ฆฌํฉํฐ๋ง์ ์งํํ๊ธฐ๋ก ๊ฒฐ์ฌํ๋ค.
(๋๊ท๋ชจ) ๋ฆฌํฉํฐ๋ง์ ์์ํด๋ณด์.
โ ํํฐ๋ง ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ค๋ฉด ์ด๋ค ๋ก์ง์ ์ง์ผํ ๊น? ํ์ฌ๋ ๋ชจ๋ ๊ฐ์ ์์ดํ ์ผ๋ก ๋ ํผ๋ฐ์ค๊ฐ ์ง์ฌ์ ธ์๊ธฐ ๋๋ฌธ์ ํํฐ๋ง์ ํ๋ฉด ๋ค๋ฅธ ๋ญํน์ ์ํ์ด ๋ณด์ฌ์ง๋๋ก ๊ตฌํ์ ํ๊ธฐ๋ก ํ๋ค.
์ฐ์ , ๊ฐ์ฅ ์์์ RankingSection์์ ์ ๋ฌผ๋ญํน ์์ดํ ๋ค์ ์์ฑํด์ค๋ค. ์์ดํ ๋ค์ ์์ฑํด์ฃผ๋ createItems ํจ์๋ฅผ RankingSection์ ๊ตฌํํด์ฃผ์.
const createItems = (): Item[] => {
return Array.from({ length: 30 }, (_, index) => ({
rankingIndex: index + 1,
imageSrc: itemThumbnail,
subtitle: 'BBQ',
title: 'BBQ ์๋
์นํจ+ํฌ๋ฆผ์น์ฆ๋ณผ+์ฝ๋ผ1.25L',
amount: 29000,
}));
};
const items = createItems();
์ด์ ‘์ฌ์ฑ์ด’, ‘๋จ์ฑ์ด’์ ๊ฐ์ด ํน์ ์นดํ ๊ณ ๋ฆฌ๋ฅผ ํด๋ฆญํ์ ๋ ํํฐ๋ง์ด ๊ตฌํ๋๋๋ก ๋ก์ง์ ์ง๋ณด์.
- useState hook์ ์ฌ์ฉํ์ฌ ์ ํ๋ ์นดํ ๊ณ ๋ฆฌ์ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ค. onCategoryChange ํจ์๋ฅผ WhoCategories์ GiftCategories์ ์ ๋ฌํด์ค๋ค.
//RankingSection.tsx
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const handleCategoryChange = (category: string) => {
setSelectedCategory(category);
};
...
<WhoCategories onCategoryChange={handleCategoryChange} />
<GiftCategories onCategoryChange={handleCategoryChange} />
...
- ํํฐ๋ง ํจ์ filteredItems ๋ฅผ ํตํด ์นดํ ๊ณ ๋ฆฌ์ ๋ฐ๋ผ ํํฐ๋ง๋ ์์ดํ ๋ค์ ํ์(์์) ์ปดํฌ๋ํธ์ธ RankingItems์ ์ ๋ฌํด์ค๋ค. (ํ์ฌ๋ ์ ๋ฌผ ์์ดํ ์ด ๋ชจ๋ ๋์ผํ๊ธฐ ๋๋ฌธ์ ๋ญํน ์ธ๋ฑ์ค๋ฅผ ๋ค๋ฅด๊ฒ ๋ณด์ฌ์ฃผ๋๋ก ์์๋ก ๊ตฌํํ๋ค. )
const filteredItems = selectedCategory
? items.filter((item) => {
if (selectedCategory === '์ ์ฒด') {
return true;
} else if (selectedCategory === '์ฌ์ฑ์ด') {
return item.rankingIndex >= 1 && item.rankingIndex <= 10;
} else if (selectedCategory === '๋จ์ฑ์ด') {
return item.rankingIndex >= 11 && item.rankingIndex <= 21;
} else if (selectedCategory === '์ฒญ์๋
์ด') {
return item.rankingIndex >= 22;
} else if (selectedCategory === '๋ฐ๊ณ ์ถ์ดํ') {
return item.rankingIndex >= 1 && item.rankingIndex <= 10;
} else if (selectedCategory === '๋ง์ด ์ ๋ฌผํ') {
return item.rankingIndex >= 11 && item.rankingIndex <= 21;
} else if (selectedCategory === '์์๋ก ๋ฐ์') {
return item.rankingIndex >= 22;
}
return false;
})
: items;
...
<RankingItems items={filteredItems} />
- RankingItems ์ ํํฐ๋ง๋ ์์ดํ ๋ค์ props๋ก ๋ฐ์์ ๋ฟ๋ ค์ค ์ ์๋๋ก ์์ ํด์ค๋ค
export const RankingItems: React.FC<RankingItemsProps> = ({ items }) => {
...}
RankingSection.tsx
<ContentWrapper>
<WhoCategories onCategoryChange={handleCategoryChange} />
<Space />
<GiftCategories onCategoryChange={handleCategoryChange} />
<RankingItems items={filteredItems} />
</ContentWrapper>
hook?
โ ”์ปดํฌ๋ํธ ์ฌ์ด์์ ์ํ ๋ก์ง์ ์ฌ์ฌ์ฉํ๊ธฐ ์ด๋ ต๋ค.”
React๋ ์ปดํฌ๋ํธ๊ฐ์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋ก์ง์ ๋ถ์ด๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ง ์๋๋ค. providers, consumers, ๊ณ ์ฐจ ์ปดํฌ๋ํธ, render props ๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ์ถ์ํ์ ๋ํ ๋ ์ด์ด๋ก ๋๋ฌ์ธ์ธ “๋ํผ ์ง์ฅ(wrapper hell)“์ ๋ณผ ๊ฐ๋ฅ์ฑ์ด ๋๋ค.
Hook์ ์ฌ์ฉํ๋ฉด ์ปดํฌ๋ํธ๋ก๋ถํฐ ์ํ ๊ด๋ จ ๋ก์ง์ ์ถ์ํํ ์ ์๋ค. ์ด๋ฅผ ์ด์ฉํด ๋ ๋ฆฝ์ ์ธ ํ ์คํธ์ ์ฌ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. Hook์ ๊ณ์ธต์ ๋ณํ ์์ด ์ํ ๊ด๋ จ ๋ก์ง์ ์ฌ์ฌ์ฉํ ์ ์๋๋ก ๋์์ค๋ค. ์ด๊ฒ์ ๋ง์ ์ปดํฌ๋ํธ ํน์ ์ปค๋ฎค๋ํฐ ์ฌ์ด์์ Hook์ ๊ณต์ ํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์ด์ค๋ค.
๋๋ก ๊ฐ๋จํ๊ฒ ์์ํ์ง๋ง ๊ด๋ฆฌํ๊ธฐ๊ฐ ํ๋ค์ด์ง๋ ์ํ ๊ด๋ จ ๋ก์ง๋ค๊ณผ ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ ์ปดํฌ๋ํธ๋ค์ ์ ์ง๋ณด์ํด์ผ ํ๋ค. ๊ฐ ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋์๋ ์์ฃผ ๊ด๋ จ ์๋ ๋ก์ง์ด ์์ฌ๋ค์ด๊ฐ๊ณ ๋ ํ๋ค. ์์๋ก componentDidMount ์ componentDidUpdate๋ ์ปดํฌ๋ํธ์์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์์ ์ ์ํํ ๋ ์ฌ์ฉ ๋์ด์ผ ํ์ง๋ง, ๊ฐ์์ componentDidMount์์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ค์ ํ๋ ๊ฒ๊ณผ ๊ฐ์ ๊ด๊ณ์๋ ๋ก์ง์ด ํฌํจ๋๊ธฐ๋ ํ๋ฉฐ, componentWillUnmount์์ cleanup ๋ก์ง์ ์ํํ๊ธฐ๋ ํ๋ค. ์ํ ๊ด๋ จ ๋ก์ง์ ํ ๊ณต๊ฐ์์ ๋ฌถ์ฌ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฐ ์ปดํฌ๋ํธ๋ค์ ์๊ฒ ๋ถ๋ฆฌํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๋ฉฐ ํ ์คํธํ๊ธฐ๋ ์ด๋ ต๋ค.
์ด๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ์ํด, ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ชผ๊ฐ๋ ๊ฒ ๋ณด๋ค๋, Hook์ ํตํด ์๋ก ๋น์ทํ ๊ฒ์ ํ๋ ์์ ํจ์์ ๋ฌถ์์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋๋๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค. (๊ตฌ๋ ์ค์ ๋ฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ๊ฒ๊ณผ ๊ฐ์ ๋ก์ง)
๐๋ก๊ทธ์ธ๊ณผ ๋ก๊ทธ์์
โ custom hook useAuth ์์ฑ
useAuth.ts์์ ์ธ์ ์คํ ๋ฆฌ์ง์ auth ์ ๋ณด์ ์ ๋ฌด๋ฅผ ํ๋จํ๊ณ isLogin ์ํ๋ฅผ ์ ๋ฐ์ดํธํด์ค๋ค.
useEffect(() => {
const auth = sessionStorage.getItem('auth');
setIsLogin(auth !== null);
}, []);
username๊ณผ password ๋ํ useAuth ํ์ผ์ ํ๋ฒ์ ๊ด๋ฆฌํ๋๋ก ์ค๊ณํ๋ค.
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
//์ด๋ฒคํธ(e)์ ํ์
์ ์ง์ ํด์ฃผ์ด์ผ ํ๋ค.
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
if (name === 'username') {
setUsername(value);
}
if (name === 'password') {
setPassword(value);
}
};
LOGIN๊ณผ LOGOUT ๊ธฐ๋ฅ๋ ๊ตฌํํด์ฃผ์. ์ฐ์ ์ ๊ฐ๋จํ๊ฒ ๋ก๊ทธ์ธ์ setItem ๋ฉ์๋๋ฅผ, ๋ก๊ทธ์์์ removeItem ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ฃผ์๋ค.
const handleLogin = (e: FormEvent) => {
e.preventDefault();
sessionStorage.setItem('auth', username);
setIsLogin(true);
navigate('/');
};
const handleLogout = (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
if (isLogin) {
sessionStorage.removeItem('auth');
setIsLogin(false);
navigate('/');
}
};
cf.
'FE > ์ฝ๋ฉ์ผ๊ธฐ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๐ณ7์8์ผ TIL๐ถ (0) | 2024.07.09 |
---|---|
๐ณ7์5์ผ TIL๐ถ (1) | 2024.07.05 |
๐ณ7์3์ผ TIL๐ถ (0) | 2024.07.03 |
๐ณ7์2์ผ TIL๐ถ (0) | 2024.07.03 |
๐ณ7์1์ผ TIL๐ถ (0) | 2024.07.01 |