티스토리 뷰

카트 유아이를 만듭니다.


routes/Cart.jsx

실제 카트 기능은 아니지만 카트처럼 보이는 구라카트 유아이를 만들어 보겠습니다.

카트를 만들어서 데이터와 펑션을 리덕스툴킷으로 콘트롤 해 보겠습니다.

카트 유아이를 빌딩 합니다.

부트스트랩을 사용하고 콘텐츠를 수정 합니다.

export default function Cart() {
  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>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>
              <button>+</button>
            </td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>
              <button>+</button>
            </td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>John</td>
            <td>Doe</td>
            <td>
              <button>+</button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  );
}

 



카트와 앱을 연결합니다.


 

App.jsx

 

카트 임포트 합니다.

 

익스클루드 컴포넌트 콘트롤 4단계

- 차일드컴포넌트 익스클루드 파일에서 익스포트

- 페어런츠컴포넌트에서 임포트

- 라우트 추가

- 링크 추가

 

import Cart from "./routes/Cart";


 

라우트 디테일 아래에 라우트를 추가 합니다.

<Route path="/cart" element={<Cart />} />


링크디테일 아래에 링크를 추가 합니다.

              <Link to="/cart" className="nav-link active" aria-current="page">
                Cart
              </Link>

TEST 실행

네브로 카트 뷰를 체크 합니다.

네브로 카트 뷰를 체크 합니다.



리액트리덕스 리덕스툴킷 설치 합니다.


리덕스툴킷을 사용하려면 리액트리덕스와 리덕스툴킷을 인스톨 합니다.
리덕스는 리액트리덕스가  품고 있으므로 인스톨 안해도 됩니다.




스토어 세팅 합니다.


src/Store.jsx

리덕스 툴킷 세팅 시작 합니다.

지금부터 카트에서 데이터를 사용할 것입니다.

리덕스툴킷을 사용할 경우 데이터는 스토어에서 콘트롤 합니다.

그러므로 루트에 스토어 파일 만듭니다.

// Redux Toolkit에서 스토어를 생성하고 설정하는 함수를 가져옵니다.
import { configureStore } from "@reduxjs/toolkit";

// configureStore 함수를 호출하여 Redux 스토어를 생성하고, 이 스토어를 모듈의 기본값으로 내보냅니다.
export default configureStore({
  // 'reducer'는 스토어가 관리할 리듀서들을 정의하는 객체입니다.
  // 현재는 비어있는 객체({})로 설정되어 있어, 아직 어떤 상태도 관리하고 있지 않아요.
  // 여기에 Slice에서 생성된 리듀서들을 추가하여 상태를 관리할 수 있습니다.
  reducer: {},
});



메인 세팅 합니다.


main.jsx

스토어를 사용하려면 사용하려는 컴포넌트를 프로바이더로 말아주어야 합니다.

리덕스툴킷이 그런 일을 도와주는 친구 입니다.

이 작업은 main.jsx 에서 진행 해야 합니다.

메인 파일 세팅 합니다.

프로바이더 임포트 합니다.

import { Provider } from "react-redux";


스토어 임포트 합니다.

import Store from "./Store";


프로바이더로 브라우저라이터 말아 줍니다.

이러면 정적 모드에서 공급 모드로 바뀌게 됩니다.

그리고 스토어 데이터 탑승 합니다.

이제부터 앱컴포넌트는 스토어를 사용할 수 있습니다.

    <Provider store={Store}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </Provider>

 

나는야 에비츄아빠

 

// React의 'StrictMode'를 불러와 개발 모드에서 잠재적인 문제를 감지하는 데 사용합니다.
import { StrictMode } from 'react';

// React DOM 클라이언트에서 'createRoot' 함수를 불러옵니다.
// 이 함수는 React 애플리케이션의 진입점을 생성하는 데 사용됩니다.
import { createRoot } from 'react-dom/client';

// 전역 스타일을 적용하기 위해 CSS 파일을 불러옵니다.
import './index.css';

// 주 애플리케이션 컴포넌트인 'App'을 불러옵니다.
import App from './App.jsx';

// React Router의 'BrowserRouter'를 불러와 URL 라우팅을 활성화합니다.
import { BrowserRouter } from 'react-router-dom';

// React-Redux의 'Provider'를 불러와 Redux 스토어를 애플리케이션 전체에 제공합니다.
import { Provider } from "react-redux";

// Redux 스토어 설정을 불러옵니다.
import Store from "./Store";

// 'createRoot'를 사용하여 HTML 파일의 'root' ID를 가진 DOM 요소에 React 애플리케이션을 렌더링합니다.
createRoot(document.getElementById('root')).render(
  // 'Provider' 컴포넌트는 Redux 스토어를 하위 컴포넌트들에 제공합니다.
  // 'store' prop을 통해 앞에서 불러온 'Store'를 연결합니다.
  <Provider store={Store}>
    // 'BrowserRouter'는 URL 경로를 기반으로 컴포넌트를 렌더링할 수 있도록 해줍니다.
    <BrowserRouter>
      // 'StrictMode'로 'App' 컴포넌트를 감싸서 개발 중 추가적인 검사를 수행합니다.
      // <StrictMode> // 주석 처리되어 있습니다. 필요에 따라 다시 사용할 수 있습니다.
        <App />
      // </StrictMode>
    </BrowserRouter>
  </Provider>
);


스토어에 슬라이스를 만듭니다.


Store.jsx

슬라이스는 하나의 스테이트이자 펑션을 담는 그릇입니다.

슬라이스는 크리에잇슬라이스가 필요 합니다.

슬라이스를 작성하기 위해 크리에잇슬라이스를 임포트 합니다.

import { createSlice, configureStore } from "@reduxjs/toolkit";


일단 슬라이스 하나만 만들어 보겠습니다.

슬라이스라고 했지만 사실 스테이트이기도 합니다.

임포트 아래에 크리에잇슬라이스 펑션으로 유저 슬라이스 빌딩 합니다.

이 슬라이스는 리듀서/액션등을 콘트롤 할 것입니다.

즉, 콘트롤 하기 좋은 스테이트를 하나 만든다고 생각하면 얼추 맞습니다.

let user = createSlice({
  name: "userss",
  initialState: "kim",
});

어떤 컴포넌트가 이 슬라이스를 사용하려면 슬라이스를 리듀서에 등록해야 합니다.

왜냐하면 그것이 리덕스툴킷의 룰이니까요.

유저스는 유저라는 네임을 가진 슬라이스를 바라 봅니다.

이제 다른 파일에서 store.users 로 접근하면 슬라이스에 담긴 데이터를 사용할 수 있습니다.

즉, 무선통신 세상이 열린 겁니다.

하지만 받는쪽에서도 세팅을 해줄것이 있습니다.

비유를 들자면 지금은 와이파이공유기를 설치한 것입니다.

와이파이를 사용하려면 내폰에서 세팅할 부분이 있을 것입니다.

export default configureStore({
  reducer: {
    users: user.reducer,
  },
});

// Redux Toolkit에서 상태를 생성하고 관리하는 'createSlice'와
// Redux 스토어를 구성하는 'configureStore' 함수를 불러옵니다.
import { createSlice, configureStore } from "@reduxjs/toolkit";

// 'createSlice' 함수를 이용해 'user'라는 이름의 '슬라이스(Slice)'를 만듭니다.
// 슬라이스는 Redux 상태의 한 조각과 그 상태를 변경하는 리듀서, 액션 등을 한 번에 정의하는 기능입니다.
let user = createSlice({
  // 이 슬라이스의 이름을 정의합니다. Redux DevTools에서 상태를 추적할 때 유용합니다.
  name: "userss",
  
  // 이 슬라이스가 관리할 초기 상태를 정의합니다.
  // 여기서는 'kim'이라는 문자열을 초기값으로 설정했습니다.
  initialState: "kim",
});

// Redux 스토어를 생성하고 내보냅니다.
export default configureStore({
  // 'reducer'는 스토어가 관리할 모든 리듀서들을 포함하는 객체입니다.
  // 이 객체에 key-value 쌍으로 리듀서를 등록합니다.
  reducer: {
    // 'users'라는 키에 위에서 만든 'user' 슬라이스의 리듀서를 등록합니다.
    // 이렇게 하면 'users'라는 이름으로 'user' 슬라이스의 상태를 스토어에서 접근할 수 있게 됩니다.
    // 예를 들어, 'store.users'로 'kim'이라는 값을 가져올 수 있습니다.
    users: user.reducer,
  },
});


카트와 스토어를 연결 하고 콘솔 찍어 봅니다.


Cart.jsx

무선통신 세상이 열렸습니다.

하지만, 몇가지 세팅은 필요 합니다.

누가 사용할지 뭐 그런 이것 저것들 세팅을 좀 해야 됩니다.

위에서 언급한 것처럼 집에서 와이파이 사용하려면 등록/라우터세팅 뭐 그런건 해야 합니다.

유즈셀렉터는 스토어 상태를 조회 할 수 있습니다.

그런데 그냥 조회 하는 것은 아닙니다.

조회하는 도구는 따로 세팅해야 합니다.

그 도구는 스테이트 입니다.

즉, 유즈셀렉터는 스테이트로 스토어 상태를 조회하는 권한을 주는 친구입니다.

유즈셀렉터 임포트 합니다.

import { useSelector } from "react-redux";


스토어와 특정 컴포넌트를 연결시켜 줄 스테이츠가 필요 합니다.

그래야 스토어를 이용할 수 있을것 같습니다.

펑션카트 내부 리턴 위에 스테이츠를 초기화 합니다.

위 코드에서 유즈셀렉터로 리덕스 스토어를 연결 했습니다.

이 스테이츠는 스토어의 모든 것을 볼 수 있습니다.

왠지 앞으로 이 스테이츠의 엄청난 활약이 기대 됩니다.

let states = useSelector((state) => state);


 

네브 카트 탭 합니다.

콘솔 찍어 봅니다.

console.log(states);

 

users가 user스테이트의 초기값인 "kim"을 제공하는군요.

{users: 'kim'}

성공입니다.

기분이 살짝 좋아졌습니다.

 

혹시 스택블리츠에서 콘솔 에러 나면 

뷰에서 카트 뷰 한 번고 보고

그래도 안되면 스택블리츠 대시보드 나갔다가 다시 들어와서 체크 합니다.

그러면 될 수도 있습니다.


// 'react-redux' 라이브러리에서 'useSelector' 훅을 가져옵니다.
// 이 훅은 Redux 스토어의 상태를 컴포넌트에서 조회할 때 사용됩니다.
import { useSelector } from "react-redux";

// 'Cart'라는 이름의 함수형 컴포넌트를 정의하고 내보냅니다.
export default function Cart() {
  // 'useSelector' 훅을 사용하여 Redux 스토어의 전체 상태를 가져옵니다.
  // 'state'는 Redux 스토어에 저장된 모든 상태 객체를 가리킵니다.
  // 이 코드는 스토어에 변화가 생길 때마다 자동으로 컴포넌트를 다시 렌더링합니다.
  let states = useSelector((state) => state);
  
  // 현재 Redux 스토어의 전체 상태를 개발자 도구 콘솔에 출력합니다.
  // 이를 통해 스토어에 어떤 데이터가 저장되어 있는지 확인할 수 있습니다.
  console.log(states);


스토어에 카트 스테이트를 추가합니다.


Store.jsx

위에서 언급했듯 슬라이스는 여러개 만들 수 있습니다.

유저배리어블 아래에 카트 스테이트를 하나 추가합니다.

// '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 },
  ],
});

리듀서 유저스 아래에 스테이트를 등록합니다.

    // 'carts'라는 키에 'cart' 슬라이스의 리듀서를 등록합니다.
    // 이렇게 하면 'store.carts'로 장바구니 상태에 접근할 수 있습니다.
    carts: cart.reducer,

// 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 },
  ],
});

// configureStore 함수를 사용해 Redux 스토어를 생성하고 내보냅니다.
export default configureStore({
  // 'reducer'는 스토어가 관리할 모든 리듀서를 포함하는 객체입니다.
  // 여기에 각 슬라이스의 리듀서를 등록합니다.
  reducer: {
    // 'users'라는 키에 'user' 슬라이스의 리듀서를 등록합니다.
    // 이렇게 하면 'store.users'로 사용자 상태에 접근할 수 있습니다.
    users: user.reducer,
    // 'carts'라는 키에 'cart' 슬라이스의 리듀서를 등록합니다.
    // 이렇게 하면 'store.carts'로 장바구니 상태에 접근할 수 있습니다.
    carts: cart.reducer,
  },
});

 


심심하니까 콘솔을 좀 괴롭혀 봅니다.

 

Cart.jsx

뷰가 안바뀌니까 심심하네요.

심심할때는 콘솔을 괴롭히면 덜 심심합니다.

스테이츠 변수 아래에 콘솔 몇개 찍어 봅니다.

  console.log(states);
  console.log(states.users);
  console.log(states.carts);

 

이렇게 나오는 군요.


// React-Redux 라이브러리에서 'useSelector' 훅을 가져옵니다.
// 이 훅은 Redux 스토어에 저장된 상태를 컴포넌트에서 효율적으로 가져올 때 사용합니다.
import { useSelector } from "react-redux";

// Cart라는 이름의 React 함수형 컴포넌트를 정의하고 내보냅니다.
export default function Cart() {
  // 'useSelector'를 사용하여 Redux 스토어의 전체 상태 객체를 'states' 변수에 할당합니다.
  // 이 훅은 스토어의 상태가 변경될 때마다 컴포넌트를 자동으로 다시 렌더링합니다.
  let states = useSelector((state) => state);
  
  // 개발자 도구 콘솔에 전체 상태 객체를 출력하여 현재 스토어의 모든 상태를 확인합니다.
  console.log(states);
  
  // 전체 상태 객체에서 'users' 상태만을 추출하여 콘솔에 출력합니다.
  // 이전에 설정한 user.reducer에 접근하는 방법입니다.
  console.log(states.users);
  
  // 전체 상태 객체에서 'carts' 상태만을 추출하여 콘솔에 출력합니다.
  // 이전에 설정한 cart.reducer에 접근하는 방법입니다.
  console.log(states.carts);


스토어데이터를 카트에서 데이터바인딩 합니다.


        <tbody>
          {states.carts.map((item, index) => (
            <tr key={index}>
              <th scope="row">{index + 1}</th>
              <td>{item.name}</td>
              <td>{item.count}</td>
              <td>
                <button>+</button>
              </td>
            </tr>
          ))}
        </tbody>

 

Cart.jsx

 

리턴 내부 티바디에 반복문 돌리고 데이터바인딩 합니다.

tr 에 키값을 주면 좋겠습니다.

 

혹시 원인 모를 에러가 나면

{states.cart.map((item, index) =>

이 부분을 지우고 다시 코딩해 보세요.

스택블리츠가 요상한 버그가 있는 것 같습니다.

문제 없이 잘 된다면 로또 사세요.

        <tbody>
          {/* states.carts 배열을 순회하며 각 항목을 테이블 행(<tr>)으로 렌더링합니다. */}
          {states.carts.map((item, index) => (
            // React가 각 항목을 고유하게 식별할 수 있도록 'key' prop을 제공합니다.
            <tr key={index}>
              {/* 장바구니 항목의 인덱스에 1을 더해 번호를 표시합니다. */}
              <th scope="row">{index + 1}</th>
              {/* 장바구니 항목의 'name'을 표시합니다. */}
              <td>{item.name}</td>
              {/* 장바구니 항목의 'count'를 표시합니다. */}
              <td>{item.count}</td>
              <td>
                <button>+</button>
              </td>
            </tr>
          ))}
        </tbody>

TEST 진행

뷰를 체크 합니다.


Completion

main.jsx

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.jsx';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from "react-redux";
import Store from "./Store";

createRoot(document.getElementById('root')).render(
  <Provider store={Store}>
  <BrowserRouter>
    <App />
  </BrowserRouter>
</Provider>
);

 

 

 

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 },
  ],
});

export default configureStore({
  reducer: {
    users: user.reducer,
    carts: cart.reducer,
  },
});

 

 

 

Cart.jsx

import { useSelector } from "react-redux";

export default function Cart() {
  let states = useSelector((state) => state);
  console.log(states);
  console.log(states.users);
  console.log(states.carts);
  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">{index + 1}</th>
              <td>{item.name}</td>
              <td>{item.count}</td>
              <td>
                <button>+</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

 

 

 

App.jsx

import { useSelector } from "react-redux";

export default function Cart() {
  let states = useSelector((state) => state);
  console.log(states);
  console.log(states.users);
  console.log(states.carts);
  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">{index + 1}</th>
              <td>{item.name}</td>
              <td>{item.count}</td>
              <td>
                <button>+</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}
 

Cart.jsx

 

import { useState } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Routes, Route, Link, Outlet } from 'react-router-dom';
import data from './data.jsx';
import Detail from './routes/Detail';
import Remove from './routes/Remove';
import axios from 'axios';
import Cart from './routes/Cart';

export default function App() {
  let [shoes, setShoes] = useState(data);

  return (
    <div className="App">
      <nav class="navbar navbar-expand-lg bg-body-tertiary">
        <div class="container-fluid">
          <a class="navbar-brand" href="#">
            Navbar
          </a>
          <button
            class="navbar-toggler"
            type="button"
            data-bs-toggle="collapse"
            data-bs-target="#navbarNavAltMarkup"
            aria-controls="navbarNavAltMarkup"
            aria-expanded="false"
            aria-label="Toggle navigation"
          >
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
            <div class="navbar-nav">
              <Link to="/" class="nav-link active" aria-current="page">
                Home
              </Link>
              <Link to="/detail" class="nav-link active" aria-current="page">
                Detail
              </Link>
              <Link to="/cart" className="nav-link active" aria-current="page">
                Cart
              </Link>
              <Link
                to="/company/manpower"
                class="nav-link active"
                aria-current="page"
              >
                Manpower
              </Link>
              <Link
                to="/company/map"
                class="nav-link active"
                aria-current="page"
              >
                Map
              </Link>
              <Link to="/remove" class="nav-link active" aria-current="page">
                account remove
              </Link>
            </div>
          </div>
        </div>
      </nav>

      <Routes>
        <Route
          path="/"
          element={
            <>
              <div className="main-bg"></div>

              <h1 className="my-5">Nike shop</h1>

              <div className="d-flex flex-column mb-3">
                {shoes.map((shoe, i) => {
                  return <Goods shoes={shoe} i={i}></Goods>;
                })}
              </div>
              <button
                onClick={() => {
                  axios
                    .get(
                      'https://raw.githubusercontent.com/lshjju/cdn/refs/heads/main/ca-shop/data2.json'
                    )
                    .then((data2) => {
                      console.log(data2.data);
                      let copy = [...shoes, ...data2.data];
                      setShoes(copy);
                    })
                    .catch(() => {
                      console.log('what the...');
                    });
                }}
              >
                VIEW MORE
              </button>
            </>
          }
        />
        <Route path="/detail/:id" element={<Detail shoes={shoes} />} />
        <Route path="/cart" element={<Cart />} />
        <Route path="/company" element={<Company />}>
          <Route path="manpower" element={<Manpower />} />
          <Route path="map" element={<Map />} />
        </Route>
        <Route path="*" element={<Nopage />} />
        <Route path="/remove" element={<Remove />} />
      </Routes>

      <div class="card m-5">
        <div class="card-header">Featured</div>
        <div class="card-body">
          <h5 class="card-title">Special title treatment</h5>
          <p class="card-text">
            With supporting text below as a natural lead-in to additional
            content.
          </p>
          <a href="#" class="btn btn-primary">
            Go somewhere
          </a>
        </div>
      </div>
    </div>
  );
}

function Goods(props) {
  return (
    <div className="p-2">
      <img
        src={
          'https://raw.githubusercontent.com/lshjju/cdn/refs/heads/main/ca-shop/s' +
          (props.i + 1) +
          '.PNG'
        }
        width="80%"
      />
      <h4 className="my-3">{props.shoes.title}</h4>
      <p>{props.shoes.price}</p>
    </div>
  );
}

function Company() {
  return (
    <div>
      <h4 className="my-3">company</h4>
      <p>It's a company</p>
      <Outlet></Outlet>
    </div>
  );
}

function Manpower() {
  return (
    <div>
      <img
        src="https://plus.unsplash.com/premium_photo-1688821131205-52f5c633ce69?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
        width="80%"
      />
    </div>
  );
}

function Map() {
  return (
    <div>
      <img
        src="https://images.unsplash.com/photo-1548345680-f5475ea5df84?q=80&w=2073&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
        width="80%"
      />
    </div>
  );
}

function Nopage() {
  return (
    <div>
      <h4 className="my-2">No page</h4>
      <p>hmmm....</p>
      <img
        src="https://cdn.maily.so/ixmvzk5qh83mee5kcjw8pp55fihe"
        width="80%"
      />
    </div>
  );
}

 

 

 

참조링크 : https://lshjju.tistory.com/291

 

ca08

카트 유아이를 만듭니다.export default function Cart() { return ( Your cart No Title Count Change 1 Mark Otto + 2 Jacob Thornton + ..

lshjju.tistory.com

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함