next + redux + typescript 간단한 예제 만들어보기
typescript를 복습하기 위해 기본적인 예제를 만들어보는 시간
next.js
,redux
,Typescript
를 사용하였습니다.
예제 생성은npx create-next-app --example with-typescript with-typescript-app
사용했습니다.
폴더 구조
├── components
│ └── Counter.tsx
├── containers
│ └── CounterContainer.tsx
├── hooks
│ └── useCounter.tsx
├── modules
│ ├── counter.ts
│ └── index.ts
├── pages
│ ├── _app.tsx
│ ├── api
│ └── index.tsx
├── public
│ ├── favicon.ico
│ └── vercel.svg
├── styles
│ ├── Home.module.css
│ └── globals.css
└── tsconfig.json
- components
UI 로직만 return 하는 컴포넌트
- containers
리덕스와 관련된 비즈니스 로직을 처리하는 컴포넌트
- hooks
커스텀 Hook 폴더
- modules
리덕스 ducks 패턴을 이용해 하나의 파일에 리듀서 관리
- pages
next에서 사용하는 pages 폴더로 라우터 기능을 지원한다
modules/counter.ts 리덕스 작성
1. action type 작성
// action type
const INCREASE = <const>'counter/INCREASE'
const DECREASE = <const>'counter/DECREASE'
const INCREASE_BY = <const>'counter/INCREASE_BY'
├── components
│ └── Counter.tsx
├── containers
│ └── CounterContainer.tsx
├── hooks
│ └── useCounter.tsx
├── modules
│ ├── counter.ts
│ └── index.ts
├── pages
│ ├── _app.tsx
│ ├── api
│ └── index.tsx
├── public
│ ├── favicon.ico
│ └── vercel.svg
├── styles
│ ├── Home.module.css
│ └── globals.css
└── tsconfig.json
UI 로직만 return 하는 컴포넌트
리덕스와 관련된 비즈니스 로직을 처리하는 컴포넌트
커스텀 Hook 폴더
리덕스 ducks 패턴을 이용해 하나의 파일에 리듀서 관리
next에서 사용하는 pages 폴더로 라우터 기능을 지원한다
// action type
const INCREASE = <const>'counter/INCREASE'
const DECREASE = <const>'counter/DECREASE'
const INCREASE_BY = <const>'counter/INCREASE_BY'
<const>
의 뜻은 타입 추론을 할 수 있도록 하기 위한 것이다. 만약 <const>
제너릭을 사용하지 않고 그대로 놔뒀을 경우 type을 string
으로 인식하게 된다.
2. action function 작성
// action function
export const increase = () => ({type: INCREASE})
export const decrease = () => ({type: DECREASE})
export const increaseBy = (diff: number) => ({type: INCREASE_BY, payload: diff})
3. initialState 및 counter reducer 작성
//initialStateType
interface initialStateType {
count: number
}
//initialState
const intialState = {count: 0}
function counter(state: initialStateType = intialState, action: CounterAction) {
switch (action.type) {
case INCREASE:
return {state: state.count + 1}
case DECREASE:
return {state: state.count - 1}
case INCREASE_BY:
return {state: state.count + action.payload}
default:
return state;
}
}
export default counter
4. 프로젝트에 리덕스 적용
modules/index.ts
import {combineReducers} from "redux";
import counter from './counter';
export type RootState = ReturnType<typeof rootReducer>;
const rootReducer = combineReducers({counter})
export default rootReducer;
pages/_app.tsx
import '../styles/globals.css'
import type {AppProps} from 'next/app'
import {Provider} from "react-redux";
import {createStore} from "redux";
import rootReducer from "../modules";
const store = createStore(rootReducer)
function MyApp({Component, pageProps}: AppProps) {
return (
<>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</>
)
}
export default MyApp
components
1. Counter.tsx 작성
import React from 'react';
interface TypeProps {
count: number
increase: () => void
decrease: () => void
increaseBy: (diff: number) => void
}
const Counter = ({count, increase, decrease, increaseBy}:TypeProps) => {
return (
<>
<h1>{count}</h1>
<button onClick={increase}>+</button>
<button onClick={decrease}>-</button>
<button onClick={() => increaseBy(5)}>increaseBy</button>
</>
);
};
export default Counter;
props로 전달받은 인자들만을 이용해 순수하게 UI 로직만 있는 코드를 작성합니다.
container
1. CounterContainer.tsx 작성
import React from 'react';
import Counter from "../components/Counter";
import {RootState} from "../modules";
import {useDispatch, useSelector} from "react-redux";
import {decrease, increase, increaseBy} from "../modules/counter";
const CounterContainer = () => {
const count = useSelector((state: RootState) => state.counter.count)
const dispatch = useDispatch();
const onIncrease = () => {
dispatch(increase());
}
const onDecrease = () => {
dispatch(decrease())
}
const onIncreaseBy = () => {
dispatch(increaseBy(5))
}
return (
<Counter count={count} increase={onIncrease} decrease={onDecrease} increaseBy={onIncreaseBy} />
);
};
export default CounterContainer;
커스텀 훅으로 프리젠테이션, 컨테이너 컴포넌트 한번에
프리젠테이션 컴포넌트와 컨테이너 컴포넌트를 분리하지 않고 커스텀 훅을 만들어 한 번에 처리할 수도 있다.
프리젠테이션, 컨테이너 컴포넌트 차이점은 링크에 잘 나와있다!
hooks/useCounter.tsx
import React from 'react';
import {useDispatch, useSelector} from "react-redux";
import {RootState} from "../modules";
import {decrease, increase, increaseBy} from "../modules/counter";
const UseCounter = () => {
const dispatch = useDispatch();
const count = useSelector((state: RootState) => state.counter.count);
const onIncrease = () => {
dispatch(increase())
}
const onDecrease = () => {
dispatch(decrease())
}
const onIncreaseBy = (diff:number) => {
dispatch(increaseBy(diff))
}
return {
count, onIncrease, onDecrease, onIncreaseBy
}
};
export default UseCounter;
기존과 같이 props로 전달해준 것이 아닌 hook을 만들어 해당하는 값들을 return 받아 Counter
컴포넌트에서 바로 사용할 수 있다.
components/Counter.tsx
import React from 'react';
import useCounter from '../hooks/useCounter'
const Counter = () => {
const {count, onIncrease, onDecrease, onIncreaseBy} = useCounter();
return (
<>
<h1>{count}</h1>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
<button onClick={() => onIncreaseBy(5)}>increaseBy</button>
</>
);
};
export default Counter
Author And Source
이 문제에 관하여(next + redux + typescript 간단한 예제 만들어보기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@chyoon0512/Typescript-간단한-예제-만들어보기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)