관리 메뉴

거니의 velog

(24) 리액트와 상품 API 서버 연동 3 본문

SpringBoot_React 풀스택 프로젝트

(24) 리액트와 상품 API 서버 연동 3

Unlimited00 2024. 3. 5. 15:32

3. 목록 페이지와 목록 컴포넌트 처리

* 목록 페이지와 목록 컴포넌트 처리 역시 이전의 Todo 예제와 유사하다. useCustomMove를 이용하면 이동과 관련된 처리를 쉽게 처리할 수 있고 FetchingModal을 이용해서 서버와의 통신 과정에 보여주도록 처리한다.

* 우선 api/productsApi.js에는 서버에서 목록 데이터를 가져오기 위한 함수를 준비한다.

import axios from "axios";
import { API_SERVER_HOST } from "./todoApi";

const host = `${API_SERVER_HOST}/api/products`;

export const postAdd = async (product) => {
  const header = { headers: { "Content-Type": "multipart/form-data" } };
  // 경로 뒤 '/' 주의
  const res = await axios.post(`${host}/`, product, header);
  return res.data;
};

export const getList = async (pageParam) => {
  const { page, size } = pageParam;
  const res = await axios.get(`${host}/list`, {
    params: { page: page, size: size },
  });
  return res.data;
};

(1) ListComponent 처리

* 실제 목록 화면 내용을 보여줄 ListComponent를 components/products/ 폴더에 추가한다.

import React, { useEffect, useState } from "react";
import { getList } from "../../api/productsApi";
import useCustomMove from "../../hooks/useCustomMove";
import FetchingModal from "../common/FetchingModal";

const initState = {
  dtoList: [],
  pageNumList: [],
  pageRequestDTO: null,
  prev: false,
  next: false,
  totoalCount: 0,
  prevPage: 0,
  nextPage: 0,
  totalPage: 0,
  current: 0,
};

const ListComponent = () => {
  const { page, size, refresh, moveToList, moveToRead } = useCustomMove();
  //serverData는 나중에 사용
  const [serverData, setServerData] = useState(initState);
  //for FetchingModal
  const [fetching, setFetching] = useState(false);

  useEffect(() => {
    setFetching(true);

    getList({ page, size }).then((data) => {
      console.log(data);
      setServerData(data);
      setFetching(false);
    });
  }, [page, size, refresh]);

  return (
    <div className="border-2 border-blue-100 mt-10 mr-2 ml-2">
      <h1>Products List Component</h1>
      {fetching ? <FetchingModal /> : <></>}
    </div>
  );
};

export default ListComponent;

* pages/products 폴더의 ListPage에 ListComponent를 추가한다.

import React from "react";
import ListComponent from "../../components/products/ListComponent";

const ListPage = () => {
  return (
    <div className="p-4 w-full bg-white">
      <div className="text-3xl font-extrabold">Products List Page</div>
      <ListComponent />
    </div>
  );
};

export default ListPage;


[목록 데이터의 출력]

* ListComponent는 API 서버에서 가져온 목록 데이터는 이미지 파일의 이름이 포함되어 있으므로 이를 화면에 출력해 줄 때 서버의 경로를 이용해야 한다.

(...)
import { API_SERVER_HOST } from "../../api/todoApi";

const host = API_SERVER_HOST;
(...)

* 화면에 데이터를 출력하는 부분은 아래와 같이 작성한다. 목록 데이터의 출력 시에 useCustomMove를 통해 만든 moveToRead를 이용해서 상품 조회 페이지로 이동이 가능하도록 구성한다.

import React, { useEffect, useState } from "react";
import { getList } from "../../api/productsApi";
import useCustomMove from "../../hooks/useCustomMove";
import FetchingModal from "../common/FetchingModal";
import { API_SERVER_HOST } from "../../api/todoApi";

const host = API_SERVER_HOST;

const initState = {
  dtoList: [],
  pageNumList: [],
  pageRequestDTO: null,
  prev: false,
  next: false,
  totoalCount: 0,
  prevPage: 0,
  nextPage: 0,
  totalPage: 0,
  current: 0,
};

const ListComponent = () => {
  const { page, size, refresh, moveToList, moveToRead } = useCustomMove();
  //serverData는 나중에 사용
  const [serverData, setServerData] = useState(initState);
  //for FetchingModal
  const [fetching, setFetching] = useState(false);

  useEffect(() => {
    setFetching(true);

    getList({ page, size }).then((data) => {
      console.log(data);
      setServerData(data);
      setFetching(false);
    });
  }, [page, size, refresh]);

  return (
    <div className="border-2 border-blue-100 mt-10 mr-2 ml-2">
      {fetching ? <FetchingModal /> : <></>}
      <div className="flex flex-wrap mx-auto p-6">
        {serverData.dtoList.map((product) => (
          <div
            key={product.pno}
            className="w-1/2 p-1 rounded shadow-md border-2"
            onClick={() => moveToRead(product.pno)}
          >
            <div className="flex flex-col h-full">
              <div className="font-extrabold text-2xl p-2 w-full ">
                {product.pno}
              </div>
              <div className="text-1xl m-1 p-2 w-full flex flex-col">
                <div className="w-full overflow-hidden ">
                  <img
                    alt="product"
                    className="m-auto rounded-md w-60"
                    src={`${host}/api/products/view/s_${product.uploadFileNames[0]}`}
                  />
                </div>
                <div className="bottom-0 font-extrabold bg-white">
                  <div className="text-center p-1">이름: {product.pname}</div>
                  <div className="text-center p-1">가격: {product.price}</div>
                </div>
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

export default ListComponent;

* 브라우저를 이용해서 상품목록을 확인한다. 아직 상품 조회에 대한 구현이 완성되지 않았으므로 상품을 클릭했을 때 에러 화면만을 보게 된다.


(2) 페이지 이동

* 페이지의 이동은 이미 useCustomMove()를 이용해서 moveToList()를 이용할 수 있고, 페이징 처리 역시 common 폴더에 PageComponent를 제작해 두었기 때문에 이를 활용하면 손쉽게 구현이 가능하다.

import React, { useEffect, useState } from "react";
import { getList } from "../../api/productsApi";
import useCustomMove from "../../hooks/useCustomMove";
import FetchingModal from "../common/FetchingModal";
import PageComponent from "../common/PageComponent";
import { API_SERVER_HOST } from "../../api/todoApi";

const host = API_SERVER_HOST;

const initState = {
  (...)
};

const ListComponent = () => {
  const { page, size, refresh, moveToList, moveToRead } = useCustomMove();
  //serverData는 나중에 사용
  const [serverData, setServerData] = useState(initState);
  //for FetchingModal
  const [fetching, setFetching] = useState(false);

  useEffect(() => {
    setFetching(true);

    getList({ page, size }).then((data) => {
      console.log(data);
      setServerData(data);
      setFetching(false);
    });
  }, [page, size, refresh]);

  return (
    <div className="border-2 border-blue-100 mt-10 mr-2 ml-2">
      (...)

      <PageComponent
        serverData={serverData}
        movePage={moveToList}
      ></PageComponent>
    </div>
  );
};

export default ListComponent;

* 화면의 아래 쪽에는 페이지 번호가 출력되는 것을 확인할 수 있다. 페이지 번호는 데이터의 수에 따라 이전/다음 이동이 가능해 진다. 마찬가지로 useCustomMove를 이용해서 moveToRead()를 이용하면 조회 화면으로 이동이 가능해 진다.