import { createContext } from 'react';
const CartContext = createContext({
items: {},
setItems: () => null,
});
export default CartContext;
import { useState } from 'react';
import CartContext from '../components/context/cartContext';
import Head from 'next/head';
import Navbar from '../components/Navbar';
function MyApp({ Component, pageProps }) {
const [items, setItems] = useState({});
return (
<>
<Head>
<link
href='https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css'
rel='stylesheet'
/>
</Head>
<CartContext.Provider value={{ items, setItems }}>
<Navbar />
<div className='w-9/12 m-auto pt-10'>
<Component {...pageProps} />
</div>
</CartContext.Provider>
</>
);
}
export default MyApp;
여기까지 하고서 vscode 깃 메뉴 변경 사항에 '+4k' 등록되어 있는 것을 발견 🙄
- 최상단에 .gitignore 파일 생성
- .gitignore에 /node_modules 폴더와 .next 폴더를 추가하고 커밋
import { useContext } from 'react';
import CartContext from './context/cartContext';
function ProductCard({ id, name, price, picture }) {
const { items, setItems } = useContext(CartContext);
const productAmount = id in items ? items[id] : 0;
const handleAmount = (action) => {
if (action === 'increment') {
const newItemAmount = id in items ? items[id] + 1 : 1;
setItems({ ...items, [id]: newItemAmount });
}
if (action === 'decrement') {
if (items?.[id] > 0) {
setItems({ ...items, [id]: items[id] - 1 });
}
}
}
return (
<div className='bg-gray-200 p-6 rounded-md'>
...
<button
className='pl-2 pr-2 bg-red-400 text-white rounded-md'
disabled={productAmount === 0}
onClick={() => handleAmount('decrement')}
>
-
</button>
<div>{productAmount}</div>
<button
className='pl-2 pr-2 bg-green-400 text-white rounded-md'
onClick={() => handleAmount('increment')}
>
+
</button>
...
</div>
);
}
export default ProductCard;
...
function ProductCard({ id, name, price, picture }) {
const { items, setItems } = useContext(CartContext);
const productAmount = items?.[id] ?? 0; // id in items를 함수 안에서 확인하도록 변경
const handleAmount = (action) => { // 인자: string
if (action === 'increment') {
const newItemAmount = id in items ? items[id] + 1 : 1;
setItems({ ...items, [id]: newItemAmount });
}
if (action === 'decrement') {
if (items?.[id] > 0) {
setItems({ ...items, [id]: items[id] - 1 });
}
}
}
return (
<div className='bg-gray-200 p-6 rounded-md'>
...
<button
... (style)
disabled={productAmount === 0} // 수량이 0이면 decrement 버튼 비활성화
onClick={() => handleAmount('decrement')}
>
-
</button>
<div>{productAmount}</div>
<button
... (style)
onClick={() => handleAmount('increment')}
>
+
</button>
...
</div>
);
}
export default ProductCard;
import { useContext } from 'react';
import Link from 'next/link';
import CartContext from './context/cartContext';
function Navbar() {
const { items } = useContext(CartContext);
const totalItemsAmount = Object.values(items).reduce((acc, cur) => acc + cur, 0);
return (
<div className='w-full bg-purple-600 p-4 text-white'>
<div className='w-9/12 m-auto flex justify-between'>
...
<div className='font-bold underline'>
<Link href='/cart' passHref>
{totalItemsAmount} items in cart
</Link>
</div>
</div>
</div>
);
}
export default Navbar;
import { useContext } from 'react';
import CartContext from '../components/context/cartContext';
import data from '../data/items';
function getFullItem(id) {
const itemIndex = data.findIndex((item) => item.id === id);
return data[itemIndex];
}
function Cart() {
const { items } = useContext(CartContext);
const totalPrice = Object.keys(items).map((id) => getFullItem(id).price * items[id]).reduce((acc, cur) => acc + cur, 0);
const itemInfo = Object.keys(items).map((id) => {
const item = getFullItem(id); // 상품 정보
return { item, amount: items[id] }; // + 상품 수량
});
return (
<div>
<h1 className='text-xl font-bold'> Total: ${totalPrice} </h1>
<div>
{itemInfo.map(({ item, amount }) => (
<div key={item.id}>
x{amount} {item.name} (${amount * item.price})
</div>
))}
</div>
</div>
);
}
export default Cart;
context API 실습 끝 🎈