๐ป ๋ฐ๋ชจ
1. yarn
2. yarn create:data # dummy data jsonํ์ผ๋ก ์์ฑ
3. yarn start
ํ์ผ์ ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
โโโ actions
|
โโโ components
| โโโ Card
| โโโ GlobalStyle
| โโโ OptionList
| โโโ TabList
| โโโ Wish
|
โโโ containers
| โโโ Products
| โโโ Header
| โโโ Main
|
โโโ data # ๋๋ฏธ ๋ฐ์ดํฐ json ํ์ผ
|
โโโ hooks
|
โโโ pages
| โโโ Products
|
โโโ store
| โโโ Product
| โโโ index.js
| โโโ reducer.js
|
โโโ utils
|
โโโ App.js
|
โโโ index.js
UI๊ตฌํ์ ์์ด์ ๊ท์น์ ์ ํ์ฌ ์ผ๊ด์ฑ์ ํ๋ณดํ๊ณ ์ ํ์ต๋๋ค.
์ญํ ์ ๋ถ๋ฆฌํจ์ผ๋ก์จ ํ๋์ ํ์ผ์ด ๋น๋ํด์ง๋ ํ์์ ๋ฐฉ์งํ๊ณ ์ฝ๋ฉ๋ฐฉ์์ ๊ท์น์ ๋ถ์ฌํ ์ ์์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ์ต๋๋ค.
ํ๋์ ํ์ด์ง์์ ๋ด๋นํ๋ ์ญํ ์ Page
, Container
, Component
๋ก ๊ตฌ๋ถ ํ๊ณ ๊ฐ๊ฐ ๋ค์๊ณผ ๊ฐ์ ์๋ฏธ๋ฅผ ๊ฐ์ง๋๋ก ํ์ต๋๋ค.
๋ง๊ทธ๋๋ก ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ํ๋์ ํ์ด์ง๋ฅผ ์๋ฏธํฉ๋๋ค. ํ์ด์ง์์ ์ ์ฒด์ ์ธ UI์ ๊ตฌ์กฐ๋ฅผ ํฌํจํ๊ณ ์ ํ์ต๋๋ค. ์ฌ๋ฌ ๊ฐ์ Container๋ Component๋ฅผ ์กฐํฉํด์ Page๋ฅผ ๊ตฌ์ฑํฉ๋๋ค.
Page๋ฅผ ๊ตฌ์ฑํ๋ ์กฐ๊ฐ์ ๋๋ค. ์ฌ๋ฌ ๊ฐ์ Container๋ Component๋ฅผ ์กฐํฉํด์ Container๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
UI๋ฅผ ๊ตฌ์ฑํ๋ ๊ฐ์ฅ ์์ ๋จ์์ ๋๋ค. ์ฌ๋ฌ ๊ฐ์ Component๋ฅผ ์กฐํฉํด์ Component๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
ํด๋น ํ๋ก์ ํธ์์ ์ฌ์ฉ๋ Product context์ state๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
{
selectedTab: DEFAULT_TAB,
tabList: [
{ name: '์ํ ๋ฆฌ์คํธ', lastTopPosition: 0 },
{ name: '์์ ๋ฆฌ์คํธ', lastTopPosition: 0 },
],
selectedSortOption: DEFAULT_OPTION,
sortOptionList: [
{ name: '์ ๋ ฌ ์์', method: defaultSort },
{ name: '๋์ ๊ฐ๊ฒฉ ์์', method: descendingSort },
{ name: '๋ฎ์ ๊ฐ๊ฒฉ ์์', method: ascendingSort },
],
fetchedProducts: [ { id, name, price, thumbnailPath } ],
wishList: { [id]: { id, name, price, thumbnailPath } }
};
wishList๋ local storage์ ์ ์ฅํ์ฌ ๊ด๋ฆฌ ํ์ต๋๋ค. ์๋ฒ์ ํต์ ์ ํ๋ค๊ณ ๊ฐ์ ํ ๋,
์ถ๊ฐ/์ ๊ฑฐ๊ฐ ๋น๋ฒํด์ง๋ฉด ์๋ฒ์ ๋ถํ๊ฐ ๋ง์ ๊ฒ์ผ๋ก ์๊ฐํ๊ณ
๊ฐ์ธ์ด ์ ํธํ๋ ์ํ ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํ์ฌ ๋ถ์์ ํ์ง ์๋๋ค๋ฉด DB์์ ๊ด๋ฆฌํ ํ์๊ฐ ์๋ค๊ณ ์๊ฐํ์ต๋๋ค.
์ํ๊ด๋ฆฌ ๋ํ UI ๊ตฌํ์ ์๊ฐํ๋ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ญํ ์ ๋๋๊ณ ์ ํ์ต๋๋ค.
react์ contextAPI์ hooks๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํํ์๊ณ ํฌ๊ฒ action
, store
, reducer
, dispatch
๊ฐ ์ํ๊ด๋ฆฌ ์ญํ ์ ๋ถ๋ดํ๋๋ก ํ์ต๋๋ค.
import Reducer from './reducer';
const Context = createContext();
const initialValue = {}; // ํด๋น state์์ ๊ด๋ฆฌํ
const Store = ({ children }) => {
const [state, dispatch] = useReducer(Reducer, initialValue);
return (
<Context.Provider value={{ state, dispatchProduct }}>
{children}
</Context.Provider>
);
};
store
๋ ์์ ๊ฐ์ ๊ตฌ์กฐ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
ํ์ ์ปดํฌ๋ํธ์์ state์ ์ ๊ทผํ ์ ์๋๋ก context๋ฅผ ์ ๊ณตํฉ๋๋ค.
store
์์ ๊ด๋ฆฌํ๋ state์ ๋ํ ์กฐ์์ ์ ์ํ reducer
๋ฅผ ํตํด ์์ฑ๋ dispatch
๋ context๋ฅผ ํตํด ์ ๊ณต๋ฉ๋๋ค.
const firstFunction = () => { ... }
const secondFunction = () => { ... }
const Reducer = (state, { type, payload }) => {
const reducers = {
[Actions.firstFunction]: firstFunction,
[Actions.secondFunction]: secondFunction,
};
const reducer = reducers[type];
return reducer ? reducer(state, payload) : state;
};
reducer
๋ dispatch
ํจ์์์ ์ธ์๋ก ๋๊ฒจ์ค action
์ ๋ฐ๋ผ ๋ค๋ฅธ ๋์์ ์ํํฉ๋๋ค.
action๏ฟฝ
์ type์ ๋ฐ๋ผ ๋ค๋ฅธ ํจ์๊ฐ ์คํ๋๊ณ ์ด์ ๋ฐ๋ผ state๊ฐ ์
๋ฐ์ดํธ ๋ฉ๋๋ค.
const firstAction = 'firstAction';
const firstActionCreator = payload => {
return { type: firstAction, payload };
};
dispatch
ํจ์์์ ์ฌ์ฉ๋ action
์ ActionCreator
๋ฅผ ํตํด ์์ฑํ๋๋ก ํ์ต๋๋ค.
const firstAction = firstActionCreator(payload);
dispatch(firstAction);
์ํ๋ฅผ ๋ณ๊ฒฝํด์ผ ๋ ๋ dispatch
ํจ์๋ฅผ ํธ์ถํจ์ผ๋ก์จ ์ด๋ฅผ ์ํํฉ๋๋ค.
์ด๋ฅผ ํตํด ์ ์ฒด์ ์ธ ์ํ๊ฐ ์
๋ฐ์ดํธ ๋๊ณ ์ํ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ ํ์ ์ปดํฌ๋ํธ์์๋ ์ด ๋ณํ๋ฅผ ๊ฐ์งํ์ฌ ๋ณ๊ฒฝ๋์๋ค๋ฉด ๋ฆฌ๋ ๋๋ง ๋๋ ์ ์ฐจ๋ฅผ ์ํํฉ๋๋ค.
์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ณผ์ ์ ์ ๋ฆฌํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. Store์์ state์ dispatch ํจ์๋ฅผ context๋ฅผ ํตํด ์ ๊ณต
2. ํ์ ์ปดํฌ๋ํธ์์ context๋ฅผ ํตํด state๋ฅผ ๋ฐ๋ก ์ฌ์ฉ๊ฐ๋ฅ
3. state๋ฅผ ๋ณ๊ฒฝํด์ฃผ์ด์ผ ํ๋ ๊ฒฝ์ฐ ์ ํฉํ action์ ์์ฑํ๊ณ ์ด๋ฅผ dispatch๋ฅผ ํตํด ํธ์ถํจ
4. reducer์์ ๋ช
์๋ action์ ํ์
์ ๋ฐ๋ผ ์ ์ ํ state ๊ด๋ฆฌ ํจ์๊ฐ ํธ์ถ๋จ
5. ํด๋น state์ ๊ด๋ จ๋์ด ์๋ ํ์ ์ปดํฌ๋ํธ์์๋ ๋ณ๊ฒฝ์ด ์ผ์ด๋จ
Intersection Obeserver API
๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํํ์ต๋๋ค. ๋ ๊ธฐ๋ฅ ๋ชจ๋ ํ๋ฉด์ ํน์ DOM element๊ฐ ๋ณด์ด๊ฒ ๋๋ ๊ฒฝ์ฐ๋ฅผ ๊ฐ์งํ ํ ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์ด์ผ ๋ฉ๋๋ค. ์ด๋ฅผ ์ํด์๋ scroll๋๋ ์๊ฐ ํ๋ฉด์ ์ด๋ป๊ฒ ๋ณด์ฌ์ง๋์ง๊ฐ ๊ตฌํ์ ๊ด๊ฑด์ด๋ผ๊ณ ์๊ฐํ์ต๋๋ค.
scroll event๋ฅผ ์ด์ฉํ์ฌ ๊ตฌํํ ์ ์์ง๋ง, scroll๋ ๋ ๋ง๋ค ๊ณผ๋ํ event๊ฐ ํธ์ถ๋ ๊ฒ์ผ๋ก ์๊ฐํ์ต๋๋ค. ๋ํ element์ ํฌ๊ธฐ์ ์์น๊ฐ์ ์์๋ด๊ธฐ ์ํด ์ฌ์ฉํ๋ getBoundingClientRect
ํจ์๋ ํธ์ถ ๋ ๋๋ง๋ค ๋ฆฌํ๋ก์ฐ ํ์์ด ๋ฐ์ํ๋ฏ๋ก ์ฑ๋ฅ์ ์ข์ง ์๋ค๊ณ ํฉ๋๋ค.
Intersection Obeserver API
๋ DOM elemetn๊ฐ ๋ทฐํฌํธ์ ๋
ธ์ถ๋์๋์ง ์ฌ๋ถ๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฒ์ฌํ์ฌ ๋ฉ์ธ ์ค๋ ๋์ ํฐ ์ํฅ์ ์ฃผ์ง ์์ ์ฑ๋ฅ์ ์ด์ ์ด ์์ต๋๋ค.
React์์ Intersection Obeserver API
๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํด custom hooks๋ฅผ ๊ตฌํํ์ฌ ์ฌ์ฉํ์ต๋๋ค.
const useIntersectionObserver = ({
root = null,
rootMargin = '0px',
threshold = 1,
handleIntersection,
}) => {
const [target, setTarget] = useState(null);
useEffect(() => {
if (!target) return;
const option = { root, rootMargin, threshold };
const io = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
entry.isIntersecting &&
handleIntersection(entry.target, observer);
});
}, option);
io.observe(target);
return () => io.unobserve(target);
}, [target, root, rootMargin, threshold, handleIntersection]);
return setTarget;
};
๊ฐ์ํ๊ณ ์ ํ๋ element์ ์ ์ฉํ option๊ณผ ์ฝ๋ฐฑํจ์๋ฅผ ์ธ์๋ก ๋๊ฒจ์ค์ผ๋ก์ ์ฌ์ฉํฉ๋๋ค. ๋ฐํ๋๋ setTarget
ํจ์๋ก ์ํ๋ element๋ฅผ Intersection Obeserver์ ๋ฑ๋กํด์ค๋๋ค.
๋ทฐํฌํธ์ target element๊ฐ ์ง์ ํ ์ค์ ๋๋ก ๊ต์ฐจ๋๋ฉด ์ธ์๋ก ๋๊ฒจ์ค ์ฝ๋ฐฑํจ์๊ฐ ์คํ๋ฉ๋๋ค.
๊ตฌํํ hooks๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ์ต๋๋ค.
const Card = () => {
...
const setTarget = useIntersectionObserver({
rootMargin: '5%',
handleIntersection,
});
function handleIntersection(target, observer) {
target.src = target.dataset.src;
observer.unobserve(target);
}
useEffect(() => {
setTarget(imgRef.current);
}, [setTarget, imgRef]);
...
}