티스토리 뷰
카운트 증가 펑션 만듭니다.
Store.jsx
카트 이니셜스테이트 아래에 카운트가 증가하는 애드카운트리듀서 추가합니다.
파라미터로 스테이트와 액션을 사용 합니다.
스테이트 즉, 현재상태에는 카트 초기값 어레이가 담겨 있습니다.
액션에는 페이로드가 담겨 있습니다.
사실 페이로드가 담고 있는 데이터는 {item.id} 입니다.
아이디로 1을 받으면 인덱스 1을 찾고 0을 받으면 인덱스 0을 찾을 것입니다.
즉, 아이디인덱스에 해당하는 스테이트 카운트를 1씩 증가시키라는 의미 입니다.
... 는 이머라이브러리가 알아서 처리했으니 땡큐 하면 됩니다.
// 'reducers' 속성은 상태를 변경하는 '리듀서 함수'들을 정의합니다.
// 각 함수는 'state'와 'action'을 인자로 받습니다.
reducers: {
// 'addCount'는 상품의 수량을 증가시키는 리듀서 함수입니다.
// 'state': 현재 상태(여기서는 cart의 initialState 배열)
// 'action': 상태 변경에 필요한 정보(payload)를 담고 있는 객체
addCount(state, action) {
// 'action.payload'는 리듀서 함수가 호출될 때 전달받은 데이터입니다.
// 여기서는 'count'를 증가시킬 상품의 인덱스를 페이로드로 받습니다.
// Immer 라이브러리 덕분에 직접 상태를 변경하는 것처럼 코드를 작성할 수 있습니다.
state[action.payload].count++;
},
콘피규어스토어 아래 다른 컴포넌트에서 이 애드카운트를 사용할 수 있게 세팅해야 합니다.
익스포트 합니다.
cart.actions 는 카트 내부 리듀서를 작동하라는 뜻입니다.
그 중에 addCount를 작동하라는 뜻입니다.
이제부터
dispatch(addCount(0))
이렇게 하면 첫 번째 상품의 수량을 증가 시킬 수 있습니다.
즉, 카트 리듀서를 작동하는 마법주문이 addCount 입니다.
// 'cart' 슬라이스에서 생성된 액션 생성자 함수들을 구조 분해 할당으로 내보냅니다.
// 이렇게 하면 다른 컴포넌트에서 이 함수('addCount')를 쉽게 불러와 사용할 수 있습니다.
// 예: 'dispatch(addCount(0))'와 같이 사용해 첫 번째 상품의 수량을 증가시킬 수 있습니다.
export let { addCount } = cart.actions;
// Redux Toolkit에서 상태를 생성하고 관리하는 'createSlice'와
// Redux 스토어를 구성하는 'configureStore' 함수를 불러옵니다.
import { createSlice, configureStore } from '@reduxjs/toolkit';
// 'user'라는 이름의 슬라이스를 만듭니다.
// 이 슬라이스는 사용자 관련 상태를 관리합니다.
let user = createSlice({
// 슬라이스의 이름을 정의합니다.
name: 'userss',
// 슬라이스의 초기 상태를 'kim'이라는 문자열로 설정합니다.
initialState: 'kim',
});
// 'cart'라는 이름의 슬라이스를 만듭니다.
// 이 슬라이스는 장바구니 관련 상태를 관리합니다.
let cart = createSlice({
// 슬라이스의 이름을 정의합니다.
name: 'cartss',
// 슬라이스의 초기 상태를 객체로 구성된 배열로 설정합니다.
// 각 객체는 장바구니에 담긴 상품의 'id', 'name', 'count'를 나타냅니다.
initialState: [
{ id: 0, name: 'White and Black', count: 2 },
{ id: 2, name: 'Grey Yordan', count: 1 },
],
// 'reducers' 속성은 상태를 변경하는 '리듀서 함수'들을 정의합니다.
// 각 함수는 'state'와 'action'을 인자로 받습니다.
reducers: {
// 'addCount'는 상품의 수량을 증가시키는 리듀서 함수입니다.
// 'state': 현재 상태(여기서는 cart의 initialState 배열)
// 'action': 상태 변경에 필요한 정보(payload)를 담고 있는 객체
addCount(state, action) {
// 'action.payload'는 리듀서 함수가 호출될 때 전달받은 데이터입니다.
// 여기서는 'count'를 증가시킬 상품의 인덱스를 페이로드로 받습니다.
// Immer 라이브러리 덕분에 직접 상태를 변경하는 것처럼 코드를 작성할 수 있습니다.
state[action.payload].count++;
},
},
});
// configureStore 함수를 사용해 Redux 스토어를 생성하고 내보냅니다.
export default configureStore({
// 'reducer'는 스토어가 관리할 모든 리듀서를 포함하는 객체입니다.
// 여기에 각 슬라이스의 리듀서를 등록합니다.
reducer: {
// 'users'라는 키에 'user' 슬라이스의 리듀서를 등록합니다.
users: user.reducer,
// 'carts'라는 키에 'cart' 슬라이스의 리듀서를 등록합니다.
carts: cart.reducer,
},
});
// 'cart' 슬라이스에서 생성된 액션 생성자 함수들을 구조 분해 할당으로 내보냅니다.
// 이렇게 하면 다른 컴포넌트에서 이 함수('addCount')를 쉽게 불러와 사용할 수 있습니다.
// 예: 'dispatch(addCount(0))'와 같이 사용해 첫 번째 상품의 수량을 증가시킬 수 있습니다.
export let { addCount } = cart.actions;
카운트추가 디스패치 합니다.
Cart.jsx
위에서 언급했던
dispatch(addCount(0))
이거 한번 사용해 보겠습니다.
그러기 위해 펑션 임포트 합니다.
import { addCount } from "../Store";
// console.log(states);
// console.log(states.users);
// console.log(states.carts);
let dispatch = useDispatch();
스테이츠아래에 디스패치를 초기화 합니다.
콘솔 괴롭히던 애들은 조용히 다가가서 마취주사 한방.
원래 <th scope="row">{index + 1}</th> 이렇게 키값으로 인덱스를 사용하고 있습니다.
이것을 이렇게 아이디 데이터바인딩으로 교체 합니다.
자동으로 부여되는 인덱스 보다 이것이 더 나을것 같습니다.
그런데 사실 이 친구는 로직에 문제를 일으킬 가능성이 있는 친구입니다.
지금은 그냥 넘어가되 일단 주의 깊게 지켜 봅니다.
<th scope="row">{item.id}</th>
<button
onClick={() => {
dispatch(addCount(item.id));
}}
>
+
</button>
플러스유아이에 이벤트 걸고 디스패치 추가합니다.
test
No 0 - Change 버튼 눌러서 수량 증가하는지 체크합니다.
잘 증가한다면 굿입니다.
Cart.jsx
// Redux 스토어에서 정의된 'addCount' 액션 생성자를 불러옵니다.
import { addCount } from '../Store';
// React-Redux 라이브러리에서 'useSelector'와 'useDispatch' 훅을 가져옵니다.
// 'useSelector': Redux 스토어의 상태를 조회할 때 사용합니다.
// 'useDispatch': Redux 스토어에 액션을 전달(발송)할 때 사용합니다.
import { useSelector, useDispatch } from 'react-redux';
// 'Cart'라는 이름의 React 함수형 컴포넌트를 정의하고 내보냅니다.
export default function Cart() {
// 'useSelector'를 사용하여 Redux 스토어의 전체 상태를 'states' 변수에 할당합니다.
// 이 훅은 스토어의 상태가 변경될 때마다 컴포넌트를 자동으로 다시 렌더링합니다.
let states = useSelector((state) => state);
// 'useDispatch'를 사용하여 'dispatch' 함수를 가져옵니다.
// 이 함수는 액션을 스토어로 보내 상태를 업데이트하는 데 사용됩니다.
let dispatch = useDispatch();
// 컴포넌트의 UI를 반환합니다.
return (
<div className="container">
<h2 className="my-4">Your cart</h2>
<table class="table table-striped">
<thead>
<tr>
<th scope="col">No</th>
<th scope="col">Title</th>
<th scope="col">Count</th>
<th scope="col">Change</th>
</tr>
</thead>
<tbody>
{/* states.carts 배열을 순회하며 각 항목을 테이블 행(<tr>)으로 렌더링합니다. */}
{states.carts.map((item, index) => (
// React가 각 항목을 고유하게 식별할 수 있도록 'key' prop을 제공합니다.
<tr key={index}>
{/* 장바구니 항목의 'id'를 표시합니다. */}
<th scope="row">{item.id}</th>
{/* 장바구니 항목의 'name'을 표시합니다. */}
<td>{item.name}</td>
{/* 장바구니 항목의 'count'를 표시합니다. */}
<td>{item.count}</td>
<td>
<button
// 버튼 클릭 시 실행될 함수를 정의합니다.
onClick={() => {
// 'dispatch' 함수를 호출하여 'addCount' 액션을 스토어로 보냅니다.
// 'addCount' 액션은 인자로 전달된 'id'에 해당하는 상품의 'count'를 증가시키는 역할을 합니다.
dispatch(addCount(item.id));
}}
>
+
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
TEST 진행
No 2 - Change 버튼 눌러봅니다.
꿈쩍도 안합니다.
펑션에 뭔가 문제가 있어 보입니다.
스토어에 따지러 갑니다.
화날때 누구한테 화내야 할지 모르면 더 화납니다.
그러고 보니 뭔가 문제가 생길때 따질 곳이 확실하니 좋군요...
스토어에 따집니다.
Store.jsx
reducers: {
addCount(state, action) {
let cartId = state.findIndex((a) => {
return a.id === action.payload;
});
state[cartId].count++;
},
},
카트슬라이스 리듀서스를 바라 봅니다.
에러난 디스패치 아이디가 2였습니다.
여기 와보니 펑션이 어레이 인덱스 2를 찾아 헤메이고 있었네요.
카트에서 아이템 아이디로 2를 받았으니까요.
당연한 겁니다.
그런데 이니셜스테이트를 보면 어레이 내부에 오브젝이 두개만 있습니다.
즉, 인덱스 2는 존재하지 않습니다.
찾아야 할 것은 어레이인덱스2가 아니고 id: 2 입니다.
즉, 카트에서는 문제 없습니다.
스토어에 와서 아이디2가 아니라 인덱스2를 찾아 헤멘 것이 문제입니다.
개선합니다.
a는 어레이 전체를 털기위해 임시로 정했습니다.
페이로드로 받은 아이디2와 같은 아이디를 가진 오브젝을 찾습니다.
잘 찾아보니 아이디2를 가진 오브젝이 있네요.
찾았으니 얘한테 펑션을 실행합니다.
참고로 findIndex()는 원하는 어레이가 몇번째 인덱스인지 찾아주는 메서드입니다.
딱 좋습니다.
즉, 아이디 2 오브젝의 카운트 데이터를 1 증가시킵니다.
import { createSlice, configureStore } from '@reduxjs/toolkit'; // '@reduxjs/toolkit' 라이브러리에서 'createSlice'와 'configureStore' 함수를 가져옵니다.
// 'createSlice'는 Redux 상태와 리듀서를 더 쉽게 정의할 수 있게 도와주며,
// 'configureStore'는 Redux 스토어를 설정하고 생성하는 역할을 합니다.
// --- 사용자(user) 상태를 관리하는 Redux Slice 정의 ---
let user = createSlice({
name: 'userss', // 이 slice의 이름입니다. Redux DevTools에서 상태를 식별할 때 사용됩니다.
initialState: 'kim', // 'user' slice의 초기 상태입니다. 여기서는 'kim'이라는 문자열로 설정되었습니다.
});
// --- 장바구니(cart) 상태를 관리하는 Redux Slice 정의 ---
let cart = createSlice({
name: 'cartss', // 이 slice의 이름입니다. 'user' slice와 마찬가지로 상태 식별에 사용됩니다.
initialState: [ // 'cart' slice의 초기 상태입니다. 상품 ID, 이름, 수량을 포함하는 객체 배열로 구성되어 있습니다.
{ id: 0, name: 'White and Black', count: 2 },
{ id: 2, name: 'Grey Yordan', count: 1 },
],
reducers: { // 이 slice에서 상태를 변경하는 함수들(리듀서)을 정의하는 객체입니다.
addCount(state, action) {
// 'addCount' 리듀서는 장바구니 항목의 수량을 증가시키는 역할을 합니다.
// 'state'는 현재 'cart' slice의 상태를 나타내며, 'action'은 호출될 때 전달되는 정보(payload)를 포함합니다.
let cartId = state.findIndex((a) => {
// 'findIndex' 메서드를 사용하여 'action.payload'로 전달된 ID와 일치하는 항목의 인덱스를 찾습니다.
// 'action.payload'는 증가시킬 항목의 ID를 담고 있습니다.
return a.id === action.payload;
});
state[cartId].count++; // 찾아낸 인덱스('cartId')에 해당하는 항목의 'count' 값을 1 증가시킵니다.
// Redux Toolkit은 immer 라이브러리를 내장하고 있어, 이처럼 상태를 직접 변경(mutate)하는 것처럼 코드를 작성해도 불변성(immutability)을 유지시켜줍니다.
},
},
});
// --- Redux 스토어 구성 및 내보내기 ---
export default configureStore({
// 'configureStore' 함수를 사용하여 Redux 스토어를 설정하고 생성합니다.
// 'export default'를 통해 이 스토어가 애플리케이션의 메인 스토어가 됩니다.
reducer: { // 스토어에 포함될 리듀서들을 정의하는 객체입니다.
// 각 키는 스토어 상태 트리의 해당 부분 이름이 되며, 값은 각 slice의 리듀서 함수입니다.
users: user.reducer, // 'user' slice의 리듀서를 'users'라는 이름으로 스토어에 추가합니다.
carts: cart.reducer, // 'cart' slice의 리듀서를 'carts'라는 이름으로 스토어에 추가합니다.
},
});
// --- 액션 생성자(Action Creator) 내보내기 ---
export let { addCount } = cart.actions;
// 'cart' slice에서 정의된 리듀서('addCount')에 해당하는 액션 생성자를 구조 분해 할당을 통해 가져와 내보냅니다.
// 이 'addCount' 함수는 컴포넌트에서 'dispatch(addCount(아이템ID))' 형태로 호출되어 해당 액션을 스토어로 보낼 수 있게 합니다.
test
넘버2 리스트 버튼을 눌러봅니다.
잘 작동하는지 체크 합니다.

Completion
Store.jsx
import { createSlice, configureStore } from '@reduxjs/toolkit';
let user = createSlice({
name: 'userss',
initialState: 'kim',
});
let cart = createSlice({
name: 'cartss',
initialState: [
{ id: 0, name: 'White and Black', count: 2 },
{ id: 2, name: 'Grey Yordan', count: 1 },
],
reducers: {
addCount(state, action) {
let cartId = state.findIndex((a) => {
return a.id === action.payload;
});
state[cartId].count++;
},
},
});
export default configureStore({
reducer: {
users: user.reducer,
carts: cart.reducer,
},
});
export let { addCount } = cart.actions;
Cart.jsx
import { useSelector, useDispatch } from "react-redux";
import { addCount } from "../Store";
export default function Cart() {
let states = useSelector((state) => state);
// console.log(states);
// console.log(states.users);
// console.log(states.carts);
let dispatch = useDispatch();
return (
<div className="container">
<h2 className="my-4">Your cart</h2>
<table class="table table-striped">
<thead>
<tr>
<th scope="col">No</th>
<th scope="col">Title</th>
<th scope="col">Count</th>
<th scope="col">Change</th>
</tr>
</thead>
<tbody>
{states.carts.map((item, index) => (
<tr key={index}>
<th scope="row">{item.id}</th>
<td>{item.name}</td>
<td>{item.count}</td>
<td>
<button
onClick={() => {
dispatch(addCount(item.id));
}}
>
+
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
심심하니까 카트 리스트 추가 리듀서도 만들어 봅니다.
Store.jsx
카트/리듀서스/애드카운트리듀서 아래에 애드아이템리듀서 추가합니다.
이것도 어차피 어레이 추가하는거니까 푸쉬쓰면 될것 같습니다.
action.payload 는 앞으로 디스패치할 데이터 { id: 1, name: "Red Knit", count: 1 } 를 바라 봅니다.
즉, 페이로드는 다양한 데이터를 담아내는 파라미터 같은 친구입니다.
addItem(state, action) {
state.push(action.payload);
},
익스포트에도 껴주면 기분 좋을것 같습니다.
export let { addCount, addItem } = cart.actions;
import { createSlice, configureStore } from '@reduxjs/toolkit'; // '@reduxjs/toolkit' 라이브러리에서 'createSlice'와 'configureStore' 함수를 가져옵니다.
// 'createSlice'는 Redux 상태와 관련 리듀서를 정의하는 과정을 간소화하며,
// 'configureStore'는 Redux 스토어를 효과적으로 설정하고 생성하는 데 사용됩니다.
// --- 사용자(user) 상태를 관리하는 Redux Slice 정의 ---
let user = createSlice({
name: 'userss', // 이 slice의 고유한 이름입니다. Redux DevTools에서 해당 상태를 식별할 때 사용됩니다.
initialState: 'kim', // 'user' slice의 초기 상태 값입니다. 여기서는 문자열 'kim'으로 설정되어 있습니다.
});
// --- 장바구니(cart) 상태를 관리하는 Redux Slice 정의 ---
let cart = createSlice({
name: 'cartss', // 이 slice의 이름입니다. 장바구니 관련 상태를 식별하는 데 사용됩니다.
initialState: [ // 'cart' slice의 초기 상태입니다. 각 객체는 상품의 ID, 이름, 수량을 포함합니다.
{ id: 0, name: 'White and Black', count: 2 },
{ id: 2, name: 'Grey Yordan', count: 1 },
],
reducers: { // 이 slice의 상태를 변경하는 함수들(리듀서)을 정의하는 객체입니다.
addCount(state, action) {
// 'addCount' 리듀서는 장바구니 내 특정 항목의 수량을 1 증가시키는 역할을 합니다.
// 'state'는 현재 'cart' slice의 상태이며, 'action'은 호출될 때 함께 전달되는 정보를 담고 있습니다.
let cartId = state.findIndex((a) => {
// 'findIndex' 메서드를 사용하여 'action.payload'로 전달된 ID와 일치하는 장바구니 항목의 인덱스를 찾습니다.
// 'action.payload'에는 수량을 증가시킬 상품의 ID가 포함되어 있습니다.
return a.id === action.payload;
});
state[cartId].count++; // 찾아낸 인덱스('cartId')에 해당하는 항목의 'count' 값을 1 증가시킵니다.
// Redux Toolkit은 내부적으로 Immer 라이브러리를 사용하므로, 상태를 직접 수정하는 방식(mutable update)으로 코드를 작성하더라도 불변성(immutability)이 자동으로 유지됩니다.
},
addItem(state, action) {
// 'addItem' 리듀서는 장바구니에 새로운 항목을 추가하는 역할을 합니다.
// 'action.payload'에는 새로 추가할 상품 객체가 포함되어 있다고 가정합니다.
state.push(action.payload); // 'state' 배열의 끝에 'action.payload' (새로운 상품 객체)를 추가합니다.
// 이 또한 Immer 덕분에 상태의 불변성이 안전하게 관리됩니다.
},
},
});
// --- Redux 스토어 구성 및 내보내기 ---
export default configureStore({
// 'configureStore' 함수를 호출하여 애플리케이션의 Redux 스토어를 설정하고 생성합니다.
// 'export default'를 통해 이 파일에서 정의된 스토어가 메인 스토어로 사용될 수 있도록 합니다.
reducer: { // 스토어에 포함될 다양한 slice들의 리듀서들을 정의하는 객체입니다.
// 객체의 키는 스토어의 전역 상태 트리에서 해당 slice가 저장될 이름을 결정합니다.
users: user.reducer, // 'user' slice에서 생성된 리듀서를 'users'라는 이름으로 스토어에 추가합니다.
carts: cart.reducer, // 'cart' slice에서 생성된 리듀서를 'carts'라는 이름으로 스토어에 추가합니다.
},
});
// --- 액션 생성자(Action Creator) 내보내기 ---
export let { addCount, addItem } = cart.actions;
// 'cart' slice의 'actions' 객체에서 'addCount'와 'addItem' 액션 생성자를 구조 분해 할당하여 내보냅니다.
// 이 액션 생성자들은 컴포넌트에서 'dispatch(addCount(ID))' 또는 'dispatch(addItem(상품객체))'와 같이 호출하여 해당 액션을 Redux 스토어로 전달하는 데 사용됩니다.
디테일에 디스패치 장착합니다.
Detail.jsx
애드아이템리듀서 임포트 합니다.
import { addItem } from "../Store";
유즈디스패치 임포트 합니다.
import { useDispatch } from "react-redux";
리턴 위에 디스패치 초기화 합니다.
let dispatch = useDispatch();
리턴 내부 버튼에 온클릭메서드로 디스패치를 장착합니다.
데이터는 일단 야매로 대충 넣습니다.
<button
className="btn btn-danger"
onClick={() => {
dispatch(addItem({ id: 1, name: "Red Knit", count: 1 }));
}}
>
CART
</button>
// React Router의 useParams 훅을 가져와 URL 파라미터를 추출합니다.
import { useParams } from 'react-router-dom';
// Redux Store에서 정의한 addItem 액션 생성자를 가져옵니다.
import { addItem } from '../Store';
// React-Redux에서 useDispatch 훅을 가져와 액션을 디스패치하는 데 사용합니다.
import { useDispatch } from 'react-redux';
// Detail 컴포넌트를 정의하고 내보냅니다. 이 컴포넌트는 부모로부터 'props'를 받습니다.
export default function Detail(props) {
// useParams 훅을 사용하여 현재 URL의 'id' 파라미터를 추출합니다.
let { id } = useParams();
// URL에서 추출한 id 값을 콘솔에 출력하여 확인합니다.
console.log(id);
// props로 전달받은 'shoes' 배열에서 URL 파라미터 id와 일치하는 항목을 찾습니다.
// find() 메서드는 주어진 판별 함수를 만족하는 배열의 첫 번째 요소를 반환합니다.
let dataId = props.shoes.find((x) => x.id == id);
// useDispatch 훅을 사용하여 'dispatch' 함수를 가져옵니다.
// 이 함수는 Redux Store로 액션을 보내 상태를 업데이트하는 데 사용됩니다.
let dispatch = useDispatch();
// JSX를 반환하여 컴포넌트 UI를 렌더링합니다.
return (
<div className="container">
<div className="row">
{/* 상품 이미지를 표시하는 영역 */}
<div className="col-md-6">
<img
// 이미지의 소스 URL을 동적으로 생성합니다.
// URL은 'https://...' + (상품 id + 1) + '.PNG' 형식으로 구성됩니다.
src={
'https://raw.githubusercontent.com/lshjju/cdn/refs/heads/main/ca-shop/s' +
(dataId.id + 1) +
'.PNG'
}
width="100%"
/>
</div>
{/* 상품의 세부 정보를 표시하는 영역 */}
<div className="col-md-6">
{/* 상품의 제목을 표시합니다. */}
<h4 className="pt-5">{dataId.title}</h4>
{/* 상품의 내용을 표시합니다. */}
<p>{dataId.content}</p>
{/* 상품의 가격을 표시합니다. */}
<p>{dataId.price}</p>
{/* 장바구니 추가 버튼 */}
<button
className="btn btn-danger"
// 버튼 클릭 시 실행될 이벤트 핸들러입니다.
onClick={() => {
// dispatch 함수를 호출하여 'addItem' 액션을 Redux Store에 보냅니다.
// 이 액션은 새로운 아이템 객체({ id: 1, name: 'Red Knit', count: 1 })를 payload로 전달합니다.
// 이를 통해 장바구니 상태에 새로운 상품이 추가됩니다.
dispatch(addItem({ id: 1, name: 'Red Knit', count: 1 }));
}}
>
CART
</button>
</div>
</div>
</div>
);
}
test
/detail/1 유알엘로 뷰 접근 합니다.
카트 버튼 탭하고 네브로 카트 탭합니다.
데이터 추가 잘 됐는지 체크 합니다.

Completion
Store.jsx
import { createSlice, configureStore } from '@reduxjs/toolkit';
let user = createSlice({
name: 'userss',
initialState: 'kim',
});
let cart = createSlice({
name: 'cartss',
initialState: [
{ id: 0, name: 'White and Black', count: 2 },
{ id: 2, name: 'Grey Yordan', count: 1 },
],
reducers: {
addCount(state, action) {
let cartId = state.findIndex((a) => {
return a.id === action.payload;
});
state[cartId].count++;
},
addItem(state, action) {
state.push(action.payload);
},
},
});
export default configureStore({
reducer: {
users: user.reducer,
carts: cart.reducer,
},
});
export let { addCount, addItem } = cart.actions;
Detail.jsx
import { useParams } from 'react-router-dom';
import { addItem } from '../Store';
import { useDispatch } from 'react-redux';
export default function Detail(props) {
let { id } = useParams();
console.log(id);
let dataId = props.shoes.find((x) => x.id == id);
let dispatch = useDispatch();
return (
<div className="container">
<div className="row">
<div className="col-md-6">
<img
src={
'https://raw.githubusercontent.com/lshjju/cdn/refs/heads/main/ca-shop/s' +
(dataId.id + 1) +
'.PNG'
}
width="100%"
/>
</div>
<div className="col-md-6">
<h4 className="pt-5">{dataId.title}</h4>
<p>{dataId.content}</p>
<p>{dataId.price}</p>
<button
className="btn btn-danger"
onClick={() => {
dispatch(addItem({ id: 1, name: 'Red Knit', count: 1 }));
}}
>
CART
</button>
</div>
</div>
</div>
);
}
디테일뷰연결
App.jsx
펑션굿즈/리턴내부/<p>{props.shoes.price}</p> 아래에 디테일링크 연결 추가 합니다.
<Link
to={'/detail/' + props.shoes.id}
className="btn btn-secondary"
aria-current="page"
>
DETAIL
</Link>
펑션앱/리턴내부/네브/ 디테일 링크 찾습니다. 삭제 합니다.
<Link to="/detail" class="nav-link active" aria-current="page">
Detail
</Link>
Reference
이 프로젝트는 코딩애플 리액트 강의를 참고하여 제작되었습니다.
https://codingapple.com/course/react-basic/
React 리액트 기초부터 쇼핑몰 프로젝트까지!
Next.js는 프론트엔드부터 서버까지 만들 수 있는 React기반 프레임워크입니다. 이것만 사용해도 풀스택 웹개발이 가능합니다. Next.js 사용시 서버사이드 렌더링이 쉽기 때문에 React, Vue만 사
codingapple.com
'프로그래밍언어 > 리엑트' 카테고리의 다른 글
| [React] 프로젝트 만들기 part8 (0) | 2026.03.22 |
|---|---|
| [React] reducer / redux / redux-toolkit (0) | 2026.03.22 |
| [React] reducer와 reducers의 차이 (0) | 2026.03.22 |
| [React] Axios (0) | 2026.03.22 |
| [React] 프로젝트 만들기 part7 (0) | 2026.03.22 |
