박주니 개발 정리

react redux를 이용해서 pagination 활용 본문

react/redux

react redux를 이용해서 pagination 활용

박주니 2023. 6. 30. 16:19
728x90
반응형

1. 먼저 redux 패키지를 설치합니다. 

npm install redux react-redux

참고 파일구조 

2. store 폴더를 생성하고 index.js에 redux 스토어를 생성하고 애플리케이션에 redux를 통합합니다. 

// src/store/index.js
import { createStore } from "redux";
import { combineReducers } from "redux";
import paginationReducer from "./reducers/paginationReducer";

// 리듀서를 복수로 관리하려면 combineReducers 함수를 사용하여 하나의 루트 리듀서로 결합합니다.
const rootReducer = combineReducers({
  pagination: paginationReducer,
});

const store = createStore(rootReducer);

export default store;

추가 설명

이부분에서는 reducer을 createStrore 기능만 한다고 보시면 됩니다.

 

3. reducers 폴더를 생성하고 paginationReducer.js를 만든 다음 페이지 관련 reducer을 만듭니다.

// src/store/reducers/paginationReducer.js

import { SET_CURRENT_PAGE, SET_ASSET } from "../actions/paginationActions";

const initialState = {
  currentPage: 1,
  asset: null,
};

const paginationReducer = (state = initialState, action) => {
  switch (action.type) {
    case SET_CURRENT_PAGE:
      return {
        ...state,
        currentPage: action.payload,
      };
    case SET_ASSET:
      return {
        ...state,
        asset: action.payload,
      };
    default:
      return state;
  }
};

export default paginationReducer;

추가 설명

  • const initialState = {currentPage: 1, asset: null}

여기서 asset은 추후에 정보를 가지고 왔을 때 페이지를 넘길 시 보여줄 정보를 관리하기 위해 구분을 해놨는데 그것보다 currpentPage를 설명을 드리면

const {currentPage, setCurrentPage} = useState(1);

의미 합니다. 어차피 redux 사용하지 않고 프론트에서 직접 다 구현한다고 생각했을 때 어떻게 전달되는 지 이해하시면 쉽게 접근하실 수 있을것입니다. 

  • paginationReducer

단순하게

setCurrentPage(...currentPage, action.payload)

입니다. 즉 초기 설정을 1로 설정을 했는데 프론트에서 action을 거쳐서 변경할 값을 받게 되면 그 값으로 교체되거나 추가가 됩니다. 배열 형식을 경우에는 추가가 될 것이고 지금처럼 배열이 아닐 경우 교체가 될 것입니다. 

4. actions 폴더를 생성하고 paginationActions.js를 만든 다음 액션 생성자 함수를 작성합니다. 

// src/store/actions/paginationActions.js

export const SET_CURRENT_PAGE = "SET_CURRENT_PAGE";
export const SET_ASSET = "SET_ASSET";

export const setCurrentPage = (page) => {
  return {
    type: SET_CURRENT_PAGE,
    payload: page,
  };
};

export const setAsset = (asset) => {
  return {
    type: SET_ASSET,
    payload: asset,
  };
};

추가 설명

먼저 이 코드 설명 앞서서 3번 reducer을 보면 paginationActions를 import 한 것을 볼 수 있을 것입니다. 프론트에서 dispatch로 받은 값을 action에서 type으로 구분하고 reducer에 보내서 값을 관리한다고 보시면 됩니다. 
5. App.js에 Provider을 통해 store 연결해서 애플리케이션 redux 적용하시면 됩니다.

import React from 'react';
import { Provider } from 'react-redux';
import store from './store';

import Pagination from './components/Pagination';

const App = () => {
  return (
    <Provider store={store}>
      <div className="App">

      </div>
    </Provider>
  );
};

export default App;

6. 프론트에 react-redux import 해서 useSelector, useDispatch를 이용해서 값을 dispatch를 해서 set하거나 selector을 이용해서 값을 가지고 온다는 관점에서 pagination을 만드시면 됩니다. 

import { React, useState } from "react";

// redux
import { useSelector, useDispatch } from "react-redux";
import {
  setCurrentPage,
} from "../../../../store/actions/paginationActions";
function TotalTicketList() {
  let [totalPage, setTotalPage] = useState(100);

  // redux
  const currentPage = useSelector((state) => state.pagination.currentPage);
  const asset = useSelector((state) => state.pagination.asset);
  const dispatch = useDispatch();
  const rowsPerPage = 20; // 한 페이지에 보여지는 로우의 개수

  const handlePageChange = (page) => {
    dispatch(setCurrentPage(page));
  };

  const renderPaginationButtons = () => {
    const totalPages = Math.ceil(totalPage / rowsPerPage);
    const visibleButtons = 10; // 한 번에 보여질 숫자 버튼의 개수

    const firstVisiblePage =
      Math.floor((currentPage - 1) / visibleButtons) * visibleButtons + 1;
    const lastVisiblePage = Math.min(
      firstVisiblePage + visibleButtons - 1,
      totalPages
    );

    const buttons = [];

    for (let i = firstVisiblePage; i <= lastVisiblePage; i++) {
      buttons.push(
        <span
          key={i}
          onClick={() => handlePageChange(i)}
          className={currentPage === i ? "active" : ""}
        >
          {i}
        </span>
      );
    }

    return buttons;
  };

  return (
    <div className="pagination">
       <button
        onClick={() => handlePageChange(currentPage - 1)}
        disabled={currentPage === 1}
       >
         이전
       </button>
			{renderPaginationButtons()}

       <button
        onClick={() => handlePageChange(currentPage + 1)}
        disabled={
        currentPage === Math.ceil(totalPage / rowsPerPage)}
        >
          다음
        </button>
   </div>
  );
}

export default TotalTicketList;
  1. react-redux에서 useSelector, useDispatch를 가지고 오고 paginationActions에서 setCurrentPage를 가지고 옵니다. 
  2. return 안에 페이지네이션 셋팅을 합니다. 
  3. renderPaginationButtons 함수에 페이지네이션 버튼 조건문을 만듭니다. 
    1. firstVisiblePage : Math.floor 을 이용해서 Math.floor((currentPage -1)/visibleButtons))을 했을 때 예를 들어서 currentPage가 5이고 visibleButtons가 10일 때 0.4의 값이 나오면 버림을 했을 경우 0이 되고 visibleButtons의 값을 곱하고 1로 더하면 값은 1이 되는 것을 볼 수 있습니다. 
    2. lastVisiblePage : Math.min은 가장 최소 값을 내보내는 내장 함수입니다.여러 조건문으로 남은 값이 10미만 여부를 따라서 조건문을 작성해 코드가 중복될 수 있었는데 이 함수를 이용하면 한줄로 체크할 수 있습니다.
      • 회고: 저는 이 방식을 몰랐을 때에는 페이지네이션 체크 숫자 따로 다음 페이지로 넘어갈 때 10보다 크거나 작거나 같은 경우에 따른 조건문을 다 작성해서 구현하다보니 rendering 함수 따로 movePage 함수 따로 만들어서 30줄이면 끝날 수 있는 것을 150줄 이상을 작성하게 되었습니다. 그래도 어떻게 돌아가는 지 확실히 알게 되어서 좋은 경험이었습니다. 
  4. handlePageChange 함수를 통해서 paginationActions에 page를 dispatch를 합니다. 
    • 추가 설명 - 여기서 dispatch는 actions에 값을 전달하는 것을 도와주는 개념이고 실질적으로는 setCurrentPage에 매개변수로 page를 전달해서 type: SET_CURRENT_PAGE에 payload가 전달한 page값을 넣습니다. 그 다음 그 값을 reducer에서 변경된 값을 넣습니다. 
  5. useSelector을 통해서 변경된 page값을 가지고 옵니다. 
const currentPage = useSelector((state) => state.pagination.currentPage);

추가 설명 - 값을 가지고 올때 state.pagination.currentPage로 한 이유는 index.js에서 reducer을 생성할 때 pagination으로 combine을 했고 reducer에서 payload 값이 currentPage에 있기 때문에 거기서 값을 가지고 온다고 보시면 됩니다. 

tip)

  • index.js - rootReducer 구성 확인
  • paginationActions에서 setCurrentPage type은 SET_CURRENT_PAGE로 해서 paginationReducer 전달
  • paginationReducer에서 type 확인 후 return action.payload 값 전달 

 

728x90
반응형
Comments