본문 바로가기
javascript & Node.js/Next.js

Redux with Nextjs (Typescript)

by V_L 2020. 9. 14.

타입맞춰주는 것과 _app.js 에서의 작업에 애를먹어서 기록해놓음.

 

 

0. 사용환경

package.json

"dependencies": {
    "next": "9.5.3",
    "next-redux-wrapper": "^6.0.2",
    "react": "^16.13.0",
    "react-dom": "^16.13.0",
    "react-redux": "^7.2.1",
    "redux": "^4.0.5"
  },
  "devDependencies": {
    "@types/next-redux-wrapper": "^3.0.0",
    "@types/node": "12.0.12",
    "@types/react": "16.8.23",
    "@types/react-dom": "16.8.4",
    "@types/react-redux": "^7.1.9",
    "redux-devtools-extension": "^2.13.8",
    "typescript": "4.0"
   },

 

 

1. 타입명시

types/state.ts

export interface ActionProps {
    type: string
}

export interface CounterState {
    value: number
}

 

2. 리듀서 생성

redux/reducer/counter.ts

import { ActionProps, CounterState } from "../../types/state";

// actions
export const INCREASE = 'counter/INCREASE';
export const DECREASE = 'counter/DECREASE';

export interface IncreaseAction {
    type: typeof INCREASE
}

export interface DecreaseAction {
    type: typeof DECREASE
}

const initialState: CounterState = { value: 0 };

export default (state = initialState, action: ActionProps) => {
    switch (action.type) {
        case INCREASE:
            return { ...state, value: state.value += 1 }
        case DECREASE:
            return { ...state, value: state.value -= 1 }

        default:
            return state;
    }
}

redux/reducer/index.ts

import { combineReducers } from "redux";
import counter from "./counter";
import { CounterState } from "../../types/state";

export type RootState = {
    counter: CounterState
}

export default combineReducers({
    counter
})

 

3. store 생성

redux/store.ts

import { createStore, applyMiddleware, Middleware, StoreEnhancer } from "redux"
import rootReducer from "./reducer";
import { MakeStore, createWrapper } from "next-redux-wrapper";

const bindMiddleware = (middleware: Middleware[]): StoreEnhancer => {
    if (process.env.NODE_ENV !== 'production') {
        const { composeWithDevTools } = require('redux-devtools-extension');
        return composeWithDevTools(applyMiddleware(...middleware));
    }
    return applyMiddleware(...middleware);
}

const makeStore: MakeStore<{}> = () => {
    const store = createStore(rootReducer, {}, bindMiddleware());
    return store
}
    

export const wrapper = createWrapper<{}>(makeStore, { debug: true });

 

4. 스토어 적용

_app.tsx

import React from 'react';
import App, { AppInitialProps, AppContext } from 'next/app';
import { wrapper } from '../redux/store';
import Head from 'next/head';

class WrappedApp extends App<AppInitialProps> {
    public static getInitialProps = async ({ Component, ctx }: AppContext) => {

        return {
            pageProps: {
                ...(Component.getInitialProps ?
                    await Component.getInitialProps(ctx)
                    :
                    {})
            },
            appProp: ctx.pathname
        }
    }

    render() {
        const { Component, pageProps } = this.props;
        return (
            <>
                <Head>
                    <title>my project</title>
                    <meta property="og:title" content="my project" key="title" />
                </Head>
                <style jsx global>{`
                    body {margin: 0}
                `}
                </style>
                
                <Component {...pageProps} />
            </>
        );
    }
}

export default wrapper.withRedux(WrappedApp);

 

5. 확인

npm run dev

크롬 콘솔창에

WrappedApp created new store with withRedux  뭐시기 하는 메세지가 뜨면 성공

 

.

.

.

.

.

.

 

 

번외

redux-saga 적용 

0. 사용환경
package.json

"dependencies": {
    "next": "9.5.3",
    "next-redux-wrapper": "^6.0.2",
    "react": "^16.13.0",
    "react-dom": "^16.13.0",
    "react-redux": "^7.2.1",
    "redux": "^4.0.5",
    "redux-saga": "^1.1.3",
  },
  "devDependencies": {
    "@types/next-redux-wrapper": "^3.0.0",
    "@types/node": "12.0.12",
    "@types/react": "16.8.23",
    "@types/react-dom": "16.8.4",
    "@types/react-redux": "^7.1.9",
    "@types/redux-saga": "^0.10.5",
    "redux-devtools-extension": "^2.13.8",
    "typescript": "4.0"
   },

 

1. saga 파일 생성

redux/sagas/index.ts

export default function* rootSaga(){
    console.log("exmaple saga");
};

 

2. store 에 미들웨어로 연결

store.ts

import { createStore, applyMiddleware, Middleware, StoreEnhancer } from "redux"
import rootReducer from "./reducer";
import { MakeStore, createWrapper } from "next-redux-wrapper";
import createSagaMiddleware from "redux-saga";
import rootSaga from "./sagas";

const bindMiddleware = (middleware: Middleware[]): StoreEnhancer => {
    if (process.env.NODE_ENV !== 'production') {
        const { composeWithDevTools } = require('redux-devtools-extension');
        return composeWithDevTools(applyMiddleware(...middleware));
    }
    return applyMiddleware(...middleware);
}

const makeStore: MakeStore<{}> = () => {
    const sagaMiddleware = createSagaMiddleware();
    const middlewares = [sagaMiddleware];
    
    const store = createStore(rootReducer, {}, bindMiddleware([...middlewares]));
    sagaMiddleware.run(rootSaga);
    return store
}
    

export const wrapper = createWrapper<{}>(makeStore, { debug: true });

 

틀린부분 지적과 조언은 언제나 환영입니다. (_ _)

'javascript & Node.js > Next.js' 카테고리의 다른 글

styled-components with Nextjs (Typescript)  (0) 2020.09.14
Next.js 개요  (0) 2020.09.07