Reducers

부가설명
리듀서 생성 API
Tags
V4

Reducers

createReducer를 사용하여 type-free 구문을 사용할 수 있도록 하기위해서 내장 types 확장하자.

[1] 내장 타입 확장

애플리케이션의 RootAction을 정의함으로써 typesafe-actions 모듈의 내장 타입을 확장할 수 있다.
내장 타입을 확장하면, createReducer API에 제네릭 타입의 인자를 전달할 필요가 없어진다.
// types.d.ts import { ActionType } from 'typesafe-actions'; export type RootAction = ActionType<typeof import('./actions').default>; declare module 'typesafe-actions' { interface Types { RootAction: RootAction; } }
// 리듀서 작성하기 // now you can use createReducer(...) // instead of // 내장 타입을 확장했다면 아래처럼 제네릭 타입 인자를 전달하지 않아도 된다. createReducer<State, Action>(...)

[2] createReducer API ( switch-case 탈출하기 )

리듀서에 switch-case로 처리하면서 좀 지저분하다는 생각을 많이 했었는데 라이브러리를 활용하여 깔끔하게 코딩할 수 있다.
createReducer API 로 type-free 구문을 작성해보자.

1) .handleAction chain으로 구성

const login = createReducer(initialState) .handleAction(changeInput, (state, { payload: { key, value } }) => ({ ...state, [key]: value })) .handleAction(actionCreator, reducer) .handleAction([actionCreator1, actionCreator2], reducer)
// using action-creators const counterReducer = createReducer(0) // state and action type is automatically inferred and return type is validated to be exact type .handleAction(add, (state, action) => state + action.payload) .handleAction(add, ... // <= error is shown on duplicated or invalid actions .handleAction(increment, (state, _) => state + 1) .handleAction(... // <= error is shown when all actions are handled // or handle multiple actions using array // 여러 액션에 대해 비슷한 처리를 할 때 유용할듯. .handleAction([add, increment], (state, action) => state + (action.type === 'ADD' ? action.payload : 1) ); // all the same scenarios are working when using type-constants // 여전히 type-constants를 이용해도 된다. const counterReducer = createReducer(0) .handleAction('ADD', (state, action) => state + action.payload) .handleAction('INCREMENT', (state, _) => state + 1); counterReducer(0, add(4)); // => 4 counterReducer(0, increment()); // => 1

2) 오브젝트 형태로 처리하기

const login = createReducer(initialState, { [CHANGE_INPUT]: (state, action) => ({ ...state, [action.payload.key]: action.payload.value }) })

[3] regular reducer 형태로 사용하기

먼저 액션들의 tagged union type을 만들어야 한다.
ActionType type-helper로 쉽게 구현할 수 있다.
import { ActionType } from 'typesafe-actions'; import * as todos from './actions'; export type TodosAction = ActionType<typeof todos>; // TodosAction이라는 tagged union type 생성
이제 state와 action에 대응하는 타입을 명시하면서 일반적인 리듀서 함수를 작성하면 된다.
export default (state: Todo[] = [], action: TodosAction) => {
이제 switch-case에서 action의 type 프로퍼티로 유니온 타입으로부터 특정 액션의 타입으로 범위를 좁힐 수 있다.
switch (action.type) { case getType(add): // below action type is narrowed to: { type: "todos/ADD"; payload: Todo; } return [...state, action.payload]; ...