728x90
반응형
NextJS에서 상태를 관리하기 수월하게 해주는 redux를 TypeScript와 함께 사용해보자.
이 포스트는 counter에 대한 state를 다루는 포스트이다.
사전 준비
create-next-app으로 프로젝트를 생성한다.
$ npx create-next-app nextredux --typescript
웹으로 설치가 잘 되었는지 확인한다.
$ npm run dev
필요한 npm 패키지를 설치한다.
$ npm i react-redux redux next-redux-wrapper
$ npm i redux-devtools-extension redux-logger --dev-save
store 폴더와 하위에 index.ts파일을 생성해준다.
/store/index.ts
import { createStore, applyMiddleware, compose } from "redux";
import { createWrapper } from "next-redux-wrapper";
import { createLogger } from "redux-logger";
import { composeWithDevTools } from "redux-devtools-extension";
import rootReducer from "reducer/index";
const configureStore = () => {
const logger = createLogger();
const enhancer = compose(composeWithDevTools(applyMiddleware(logger)));
const store = createStore(rootReducer, enhancer);
return store;
};
const wrapper = createWrapper(configureStore, { debug: true });
export default wrapper;
아직 reducer 폴더를 만들지 않았기 때문에 오류가 뜬다. 천천히 해보자.
만든 store를 _app.tsx 파일에 wrapper 적용을 하자.
_app.tsx
import { AppProps } from "next/app";
import { NextPage } from "next";
import wrapper from "../store"; //좀전에 만든 store.ts 파일
const MyApp: NextPage<AppProps> = ({ Component, pageProps }: AppProps) => {
return (
<>
<Component {...pageProps} />
</>
);
};
export default wrapper.withRedux(MyApp);
interfaces폴더를 아래와 같이 생성한다.
index.ts파일을 수정한다.
/store/interfaces/index.ts
export * from "./counter/counter.interfaces";
export * from "./counter/counterAct.interfaces";
RootState.ts파일을 수정한다.
/store/interfaces/RootState.ts
import { CounterState } from "./index";
export interface RootStateInterface {
counter: CounterState;
}
counter.interfaces.ts 파일을 수정한다.
/store/interfaces/counter/counter.interfaces.ts
export interface CounterState {
count: number;
}
counterAct.interfaces.ts 파일을 수정한다.
/store/interfaces/counter/counterAct.interfaces.ts
export enum actionTypesCounter {
COUNTER_INCREMENT = "COUNTER_INCREMENT", // 숫자 + 1
COUNTER_DECREMENT = "COUNTER_DECREMENT", // 숫자 - 1
COUNTER_RESET = "COUNTER_RESET", // 초기화
}
export type ActionsCounter = CounterIncrement | CounterDecrement | CounterReset;
export interface CounterIncrement {
type: actionTypesCounter.COUNTER_INCREMENT;
}
export interface CounterDecrement {
type: actionTypesCounter.COUNTER_DECREMENT;
}
export interface CounterReset {
type: actionTypesCounter.COUNTER_RESET;
}
interfaces는 완성되었다. 이번엔 reducer를 만들어보자.
index.ts 파일을 수정한다.
/store/reducer/index.ts
import { combineReducers, Reducer, AnyAction } from "redux";
import { RootStateInterface } from "../interfaces/RootState";
import counter from "./counter";
const rootReducer: Reducer<
RootStateInterface,
AnyAction
> = combineReducers<RootStateInterface>({
counter,
});
export default rootReducer;
export type RootState = ReturnType<typeof rootReducer>;
counter.ts 파일을 수정한다
/store/reducer/counter.ts
import { HYDRATE } from "next-redux-wrapper";
import {
CounterState,
actionTypesCounter,
ActionsCounter,
} from "../interfaces";
export const initialState: CounterState = {
count: 0,
};
interface HydratePayload {
counter: CounterState;
}
const counter = (
state = initialState,
action: ActionsCounter | { type: typeof HYDRATE; payload: HydratePayload },
): CounterState => {
switch (action.type) {
case HYDRATE:
return { ...state, ...action.payload.counter };
case actionTypesCounter.COUNTER_INCREMENT:
return {
...state,
...{ count: state.count + 1 },
};
case actionTypesCounter.COUNTER_DECREMENT:
return {
...state,
...{ count: state.count - 1 },
};
case actionTypesCounter.COUNTER_RESET:
return {
...state,
...{ count: initialState.count },
};
default:
return state;
}
};
export default counter;
그다음 pages/counter/index.tsx 파일을 만든다.
pages/counter/index.tsx
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootStateInterface } from "../../store/interfaces/RootState";
import { CounterState } from "../../store/interfaces";
import { actionTypesCounter } from "../../store/interfaces/counter/counterAct.interfaces";
const Counter = () => {
const { count } = useSelector(
(state: RootStateInterface): CounterState => state.counter,
);
const dispatch = useDispatch();
const handleClick = (num: number) => {
if (num === 1) {
dispatch({type : actionTypesCounter.COUNTER_INCREMENT});
} else if (num === 0) {
dispatch({type : actionTypesCounter.COUNTER_DECREMENT});
} else if (num === 2) {
dispatch({type : actionTypesCounter.COUNTER_RESET});
}
};
return (
<div>
<div>현재값:{count}</div>
<div>
<button onClick={() => handleClick(1)}>+</button>
<button onClick={() => handleClick(0)}>-</button>
<button onClick={() => handleClick(2)}>reset</button>
</div>
</div>
);
};
export default Counter;
실행해본다.
정상적으로 카운트state가 버튼 클릭에따라 바뀌는 것을 확인할 수 있다.
액션을 만들어서 State를 다루는 방법은 Nest - Next 카테고리에서 확인할 수 있다.
728x90
반응형
'Front-End > Next.js' 카테고리의 다른 글
Next.js | 기본기능 | userAgent 정보 확인하기 (0) | 2021.11.03 |
---|---|
Next.js | 기본기능 | Built-In CSS Support(SCSS) (0) | 2021.11.02 |
Next.js | 기본기능 | 환경 변수 (0) | 2021.10.13 |
Next.js | API 경로 (0) | 2021.10.13 |
Next.js | 라우터 | Imperatively (0) | 2021.10.13 |