우아한 테크러닝 3기 React & TypeScript 2회차 (3)

Happy_Nerd·2020년 9월 18일
0
post-thumbnail

Redux 만들어보기


index.js

import { createStore, actionCreator } from "./redux";

const INIT = "init";
const INCREMENT = "increment";
const RESET = "reset";

function reducer(state = {}, { type, payload }) {
    switch (type) {
        case INIT: {
            return {
                ...state,
                count: payload.count,
            };
        }
        case INCREMENT:
            return { ...state, count: state.count ? state.count + 1 : 1 };
        case RESET:
            return {
                ...state,
                count: 0,
            };
        default:
            return { ...state };
    }
}

/* * * * * * * * * * * * * * * * * * * * * * * * * *
 * 헬퍼 함수                                       *
 * init : store의 값을 count로 초기화              *
 * increment : store의 count를 1증가 또는 1로 설정 *
 * reset : store의 count를 0으로 초기화            *
 * * * * * * * * * * * * * * * * * * * * * * * * * */

function init(count) {
    store.dispatch(actionCreator(INIT, { count }));
}

function increment() {
    store.dispatch(actionCreator(INCREMENT));
}

function reset() {
    store.dispatch(actionCreator(RESET));
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 스토어의 생성 및 subscribe를 사용한 state 로깅                    *
 * 1. createStore 함수로 스토어를 생성                               *
 * 2. getState 함수를 사용해 값을 출력하는 함수 작성                 *
 * 3. 스토어의 subscribe 메서드를 이용해 2번에서 작성한 함수로 구독  *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

const store = createStore(reducer);

function update() {
    console.log(store.getState());
}

store.subscribe(update);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 스토어의 값을 변경하는 액션을 실행시키는 방법                       *
 * 1. type과 payload을 포함한 액션을 dispatch                          *
 * 2. action을 반환하는 actionCreator 헬퍼 함수를 사용한 후 dispatch   *
 * 3. payload를 전달받아 dispatch까지 해주는 헬퍼 함수 이용            *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

store.dispatch({ type: INCREMENT }); // { count: 1 }
store.dispatch(actionCreator(INCREMENT)); // { count: 2 }
increment(); // { count: 3 }

store.dispatch({ type: INIT, payload: { count: 5 } }); // { count: 5 }
store.dispatch(actionCreator(INIT, { count: 0 })); // { count: 0 }
init(10); // { count: 10 }

store.dispatch({ type: RESET }); // { count: 0 }
store.dispatch(actionCreator(RESET)); // { count: 0 }
reset(0); // { count: 0 }

redux.js

// 스토어 만드는 함수
export function createStore(reducer) {
    let state;
    const listener = [];
    const publish = () => {
        listener.forEach(({ subscriber, context }) => {
            subscriber.call(context);
        });
    };
    const dispatch = (action) => {
        state = reducer(state, action);
        publish();
    };
    const subscribe = (subscriber, context = null) => {
        listener.push({ subscriber, context });
    };
    const getState = () => ({ ...state });

    return {
        getState,
        dispatch,
        subscribe,
    };
}

// 액션생성함수
export function actionCreator(type, payload = {}) {
    return {
        type,
        payload: { ...payload },
    };
}

action : 상태 변화가필요할 때 객체의 형태로 발생시킴. type 필드는 필수적으로 가지고 있어야하고 추가적으로 다른 필드도 가질 수 있다.

{ type: 'increment' }

or

{
  type: 'increment',
  text: '증가'
}

action 생성함수: 액션을 만드는 함수. 액션 객체를 만들 때 필요한 데이터를 인자로 받아 액션 객체를 만들어 리턴해주는 함수.

// 화살표 함수로도 만들 수 있음
const createAction = text => ({
	type: 'increment',
  	text
});

store: createStore 함수를 통해 만들 수 있다. state에 직접 접근하지 못하도록 클로저를 이용하기 때문에 상태를 보려면 getState 함수를 통해야 한다.
reducer: 현재의 상태와 전달받은 액션을 통해 새로운 상태를 만들어서 store에 저장한다. store에 있는 state는 반드시 reducer를 통해서 변경되어야 한다.
dispatch: store의 내장함수 중 하나이다. 액션을 파라미터로 전달하면서 호출을 하면 스토어는 리듀서 함수를 실행시켜서 해당 액션을 참고하여 새로운 상태를 만든다.
subscribe: store의 내장 함수 중 하나. 함수 형태의 값을 파라미터로 받고, 액션이 디스패치 되었을 때마다 전달받은 함수를 호출한다

(참고: Redux (1) 소개 및 개념정리)

0개의 댓글