본문 바로가기
공부/프로그래밍

[react] react + nextjs + redux + typescript 설정하기(redux toolkit 사용)

by demonic_ 2020. 12. 25.
반응형

react + redux + typescript를 이용한 프로젝트 생성을 알아보려 한다

 

타입스크립트가 적용되는 reaxt + nextjs 를 설치한다.

npx create-next-app --example with-typescript test-app

 

 

npx 를 사용하는 이유는 이전 포스팅을 참조하면 좋겠다.

참조: lemontia.tistory.com/987

 

[npm] npm 대신 npx 를 사용하는 이유

npm을 사용하려면 글로벌 모듈로 설정해서 사용하기 때문이다. 글로벌이라는 것은 내 컴퓨터 안에 모든 프로젝트가 접근가능하도록 설정하는건데, 다음과 같은 방법으로 설치할 수 있다. npm insta

lemontia.tistory.com

 

redux, redux toolkit, immer 등 추가 설치한다

npm i redux react-redux immer @types/react-redux typesafe-actions

 

생성된 폴더로 이동하여 서버를 실행한다.

cd test-app
npm run dev

 

 

다음 로그가 뜨면 서버실행에 성공한 것이다.

localhost:3000 으로 접속가능하다

> with-typescript@1.0.0 dev /Users/dgpark/git/side-project/test-app
> next

ready - started server on http://localhost:3000
event - compiled successfully
event - build page: /
wait  - compiling...
event - compiled successfully

localhost:3000 화면 모습

 

타입스크립트가 있는지 즉시 확인 가능하다,

 

파일을 열어 설정내용을 한번 보는걸 추천

{
  "compilerOptions": {
    "allowJs": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "lib": ["dom", "es2017"],
    "module": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "target": "esnext"
  },
  "exclude": ["node_modules"],
  "include": ["**/*.ts", "**/*.tsx"]
}

 

 

# Reducer 등록

 

이제 파일을 총 4개 생성한다

1) reducer 파일

2) reducer 설정 파일

3) store 생성 파일

2) _app.tsx 파일

 

 

Reducer 파일 생성 => 설정에 등록 => Store 생성 => _app.js 에 등록하는 과정이다

 

reducers 폴더를 만든 후, testReducer.ts 파일을 생성한다.

 

 

 

간단한 기능이 있는 Reducer를 하나 등록한다.

리듀서 등록 방법을 모른다면 이전글을 참조하면 도움이 된다.

lemontia.tistory.com/986

 

[react + typescript] redux toolkit 사용하기(createAction , ActionType , createReducer)

redux toolkit은 Redux의 공식 개발도구다. 액션 생성자, 리듀서 자체는 단순 함수인데 문제는 코드가 엄청나게 늘어난다는 불편함이 있다. redux toolkit을 사용하면 코드를 줄이는데 도움을 준다(그리

lemontia.tistory.com

 

testReducer.ts 파일 생성 및 아래코드를 넣는다

import {
    createAction
    , ActionType
    , createReducer
} from 'typesafe-actions';

// 상태의 타입 선언
interface TestReducer {
    no: number;
    text: string;
}

// 상태 초기화
const initialState: TestReducer = {
    no: 0,
    text: "hello"
}

// 액션타입 선언
export const RESET_TEXT = "testReducer/RESET_TEXT";
export const ADD_TEXT = "testReducer/ADD_TEXT";
export const REMOVE_TEXT = "testReducer/REMOVE_TEXT";

// 액션함수 선언
export const resetText = createAction(RESET_TEXT)();
export const addText = createAction(ADD_TEXT)<TestReducer>()
export const removeText = createAction(REMOVE_TEXT)()

// 액션 객체타입
export const actions = {resetText, addText, removeText}
type TestReducerActions = ActionType<typeof actions>;

// 리듀서 추가
const testReducer = createReducer<TestReducer, TestReducerActions>(initialState, {
    [RESET_TEXT]: () => ({
        no: 0,
        text: ""
    }),
    [ADD_TEXT]: (state, action) => {
        console.log(state.text)
        return ({
            no: action.payload.no,
            text: action.payload.text
        })
    },
    [REMOVE_TEXT]: (state) => ({
        no: state.no,
        text: ""
    })
})

export default testReducer;

 

 

 

Reducer를 설정파일에 등록한다

같은 폴더 내 index.ts 파일을 만든다

 

import { combineReducers } from "redux";
import testReducer from "./testReducer";

const rootReducer = combineReducers({
    testReducer
})

export default rootReducer;

export type RootState = ReturnType<typeof rootReducer>;

 

 

store를 생성할 파일을 추가한다. 혹은 _app.tsx 내에 코드를 넣어놔도 상관없지만 여기선 설정을 분리했다.

configureStore.ts 생성

import { compose, createStore, Store } from "redux";
import rootReducer from ".";
      
declare global {
    interface Window {
      __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;
    }
}

// store 생성
export default function configureStore():Store {
    const composeEnhancers = typeof (window as any) !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    const store = createStore(
        rootReducer,
        composeEnhancers()
    );
    return store;
}

 

설정한 것중에 __REDUX_DEVTOOLS_EXTENSION_COMPOSE__ 은 크롬에서 테스트할때 Redux 확장프로그램을 활용하기 위해 넣은 것이다. 사용하지 않는다면 createStore(rootReducer) 로만 생성해도 된다.

추후 운영, 개발서버 분리해서 띄우는 설정도 필요할텐데, 그건 추후에 포스팅 하는 것으로.

 

그럼 이제 생성한 파일들을 _app.tsx 파일에 등록해야 한다. 다음 파일을 생성한다.

import React from 'react'
import App, { AppContext, AppProps } from 'next/app'
import { Provider } from 'react-redux'
import configureStore from '../reducers/configureStore'

// store 설정파일 로드
const store = configureStore()

const TestApp = ({Component, pageProps}: AppProps) => {
    return (
        <Provider store={store}>
            <Component {...pageProps} />
        </Provider>
    )
}

TestApp.getInitialProps = async (appContext: AppContext) => {
    const appProps = await App.getInitialProps(appContext);

    return {...appProps}
}


export default TestApp

 

 

이제 설정이 끝났다.

test 컴포넌트를 만들어서 잘 작동하는지 확인해보자

pages 폴더 아래 test.tsx 파일을 생성한다

import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../reducers";
import { actions, RESET_TEXT } from "../reducers/testReducer";

const Test = () => {
    const {no, text} = useSelector((state: RootState) => state.testReducer)

    const dispatch = useDispatch()

    useEffect(() => {

        dispatch({
            type: RESET_TEXT
        })
    }, [])


    const addTextHandler = () => {
        const value = "world"

        dispatch(actions.addText({no: 10, text: value}))
    }

    return (
        <>
            <p>no: {no}</p>
            <p>text: {text || ""}</p>
            <div>
                <button onClick={addTextHandler}>
                    버튼
                </button> 
            </div>
        </>
    )
}

export default Test;

 

localhost:3000/test 으로 접속해서 화면을 확인해보자.

 

버튼을 누르면 Reducer가 제대로 동작하는 것을 확인할 수 있다.

 

여기까지가 설정 완료다. 이제 프로젝트 내에 불필요한 파일을 정리하자.

 

pages/index.tsx 파일 정리

import Link from "next/link";

const IndexPage = () => (
  <>
    <p>React 시작하기</p>
    <Link href="/test">
      <a>Reducer Test 페이지 이동</a>
    </Link>
  </>
)

export default IndexPage

다음과 같이 화면이 뜬다

 

폴더 삭제: pages/users , pages/api

파일 삭제: about.tsx

 

최종 구성은 다음과 같다

끝.

 

 

해당 설정은 Github에 올렸습니다.

github.com/lemontia/react-redux-sample

 

lemontia/react-redux-sample

Contribute to lemontia/react-redux-sample development by creating an account on GitHub.

github.com

 

반응형

댓글