Codesandbox
나 Codepen
에서 React-Redux로 구현된 다양한 예제들이 많이 보인다. 각자만의 방식으로 작성되어있어 내 것으로 만들기에는 약간 시간이 필요했었다. 그래서 이번에 나만의 방법으로 React-Redux
와 Hook
을 활용해 Tab을 구현해 보려한다.
우선 Redux의 작동원리를 다시 알아보자면 간단하게는 아래와 같다.
사용자는 어떠한 입력을 하게되면 dispatch
를 통해 action
을 Reducer
로 전달한다. Reducer
는 정해진 타입에따라 Store
내의 State
의 저장된 상태값을 바꿔 반환한다. dispatch
, State
등 다양한 일을 관리해주는 핵심 요소가 바로 Store
라는 곳이다.
store폴더를 만들어 작성하거나 아니면 가장 최상단 컴포넌트에 작성해준다.
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
라이브러리에서 제공되는 컴포넌트로React
가store
에 쉽게 연동되게 도와주는 역할을 한다.
thunk : thunk 는 리덕스에서 비동기 작업을 위해 사용하는 미들웨어이고, 액션 객체가 아닌 함수를 디스패치할 수 있다. 현재 사용하는 이유는 아직까지는
Redux 개발툴
만 사용하기위해 적용함.
export const TABS = {
ACTIVE_TAB: "ACTIVE_TAB",
};
export const activeTabs = (tabs) => {
return { type: TABS.ACTIVE_TAB, activeTab: tabs };
};
activeTab
의 역할은 선택한 요소의 인덱스를 전달해주는 역할이다.
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로 관리 할 수 있게 해준다.
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
이 완성되었다.