React-Redux + Hook을 활용해 Tab만들어보기

캡틴 노드랭크·2021년 8월 2일
0

Project

목록 보기
3/7

CodesandboxCodepen에서 React-Redux로 구현된 다양한 예제들이 많이 보인다. 각자만의 방식으로 작성되어있어 내 것으로 만들기에는 약간 시간이 필요했었다. 그래서 이번에 나만의 방법으로 React-ReduxHook을 활용해 Tab을 구현해 보려한다.

React-Redux Tabs

우선 Redux의 작동원리를 다시 알아보자면 간단하게는 아래와 같다.

사용자는 어떠한 입력을 하게되면 dispatch를 통해 actionReducer로 전달한다. Reducer는 정해진 타입에따라 Store내의 State의 저장된 상태값을 바꿔 반환한다. dispatch, State 등 다양한 일을 관리해주는 핵심 요소가 바로 Store라는 곳이다.

Store 작성

store폴더를 만들어 작성하거나 아니면 가장 최상단 컴포넌트에 작성해준다.

  • index.js

import React from "react";
import ReactDOM from "react-dom";
import { createStore, applyMiddleware } from "redux";

import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
const middleware = [thunk];
const store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(...middleware))
);

ReactDOM.render(
  <Provider store={store}>
    <GlobalStyles />
    <MainContent />
  </Provider>,
  document.getElementById("root")
);

Provider : Provider 컴포넌트는 React-redux라이브러리에서 제공되는 컴포넌트로 Reactstore에 쉽게 연동되게 도와주는 역할을 한다.

thunk : thunk 는 리덕스에서 비동기 작업을 위해 사용하는 미들웨어이고, 액션 객체가 아닌 함수를 디스패치할 수 있다. 현재 사용하는 이유는 아직까지는 Redux 개발툴만 사용하기위해 적용함.

Action과 Reducer 작성

  • tab_action

  • ./_action/tabs_action.js

export const TABS = {
  ACTIVE_TAB: "ACTIVE_TAB",
};

export const activeTabs = (tabs) => {
  return { type: TABS.ACTIVE_TAB, activeTab: tabs };
};

activeTab의 역할은 선택한 요소의 인덱스를 전달해주는 역할이다.

  • tab_Reducer

  • ./_reducer/tabs_reducer.js
import { combineReducers } from "redux";
import { TABS } from "../_actions/types";

const initialState = {
  activeTab: 0,
};

export default function tabs_Reducer(state = initialState, action) {
  switch (action.type) {
    case TABS.ACTIVE_TAB:
      return {
        ...state,
        activeTab: action.activeTab,
      };
    default:
      return state;
  }
}

const rootReducer = combineReducers({

  tabs_Reducer,
});

export default rootReducer;

combineReducers는 액션에 따른 다양한 reducer를 작성하게 되는데, 이를 합쳐 하나의 Reducer로 관리 할 수 있게 해준다.

렌더링할 컴포넌트 작성

  • MainContent

import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { activeTabs } from "../../_actions/tab_action";
import {
  StyledMainContainer,
  DefaultScreen,
  TabList,
  TabMenu,
  TabContainer,
} from "./styles/StyledTabContent";

const tabTitle = ["탭1", "탭2", "탭3", "탭4", "탭5"];

const tabContent = {
  0: <ContentA />,
  1: <ContentB />,
  2: <ContentC />,
  3: <ContentD />,
};

export default function MainContent() {
  const dispatch = useDispatch();
  const activeTab = useSelector((state) => state.tabs_Reducer.activeTab);
  console.log(useSelector((state) => state.tabs_Reducer.activeTab));

  return (
    <StyledMainContainer>
      <DefaultScreen>
        <TabContainer>
          <TabList>
            {tabTitle.map((menu, idx) => (
              <TabMenu key={idx} onClick={() => dispatch(activeTabs(idx))}>
                {menu}
              </TabMenu>
            ))}
          </TabList>
          {tabContent[activeTab]}
          {console.log(tabContent[activeTab])}
        </TabContainer>
      </DefaultScreen>
    </StyledMainContainer>
  );
}

useDispatch() 는 Hook이전에 액션을 발생시키려면 mapStateToProps()를 사용해줬었다. 이제는 useDispatch()를 사용하여 간편하게 구현이 가능하다.

useSelector()Store내의 state를 조회하기 위한 함수이다. 위 코드에서 useSelector((state) => state.tabs_Reducer) 이부분을 콘솔로그로 찍어보면 state에 저장된 상태를 조회 할 수 있다.

반복 작업을 줄이기 위해 map 메소드를 사용했으며 tabTitle중 하나를 클릭 할 경우 index가 변경된다. 해당 index에 따른 컴포넌트들을 렌더링을 해준다.

이렇게 간단한 tab이 완성되었다.

profile
다시 처음부터 천천히... 급할필요가 없다.

0개의 댓글