Redux-Toolkit : Basic Tutorial

R

원문 : https://redux-toolkit.js.org/tutorials/basic-tutorial

주의 : 제가 이해하기 쉬운 방식으로 번역 및 첨언했습니다.


Introduction: Writing a Counter Application

Redux "Counter-Vanilla" Example

function counterReducer(state, action) {
  if (typeof state == 'undefined') { return 0 }
  switch (action.type) {
    case 'INCREMENT': return state + 1
    case 'DECREMENT': return state -1
    default: return state
  }
}
var store = Redux.createStore(counterReducer);
document.getElementById('incrementBtn').addEventListener('click', function(){
  store.dispatch({type: 'INCREMENT'});
});

대~충 Counter를 만들어보았다.

A More Typical Counter Example

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
function increment() {
  return { type: INCREMENT }
}
function decrement() {
  return { type: DECREMENT }
}
function counterReducer(state = 0, action) {
  console.log(action);
  switch (action.type) {
    case INCREMENT: return state + 1
    case DECREMENT: return state - 1
    default: return state
  }
}
var store = Redux.createStore(counterReducer);
document.getElementById('incrementBtn').addEventListener('click', function(){
  store.dispatch(increment());
});

쫌 더 실제프로젝트에서 쓸 수 있게끔 만들었다. action생성자 함수도 있고, action.type도 상수로 두었다. 하지만, INCREMENT라는 상수를 만드는것도, 생성자 함수를 만드는것도 모두 귀찮은 일이다. 매번 switch안에 case를 써주는 일도!

Introducing: configureStore

configureStore는 내부적으로 createStore를 쓴다. 하지만, configureStore는 안에서 Redux DevTools Extension과 몇가지 유용한 middleware를 자동으로 설정해주는 이점이 있다.

// Before:
const store = createStore(counterReducer)
// After:
const store = configureStore({
  reducer: counter
Reducer
})

위의 코드에서 보이듯이, 인자값으로 객체를 넣어줘야한다.

Introducing: createAction

// 원래 방식
const INCREMENT = 'INCREMENT'
function incrementOriginal() {
  return { type: INCREMENT }
}
console.log(incrementOriginal())
// {type: "INCREMENT"}
// 더 편한 방식 : action creator를 만들어주는 createAction함수 사용.
const incrementNew = createAction('INCREMENT')
console.log(incrementNew())
// {type: "INCREMENT"}

엄밀히 말하면 createActionaction object를 만들어 주는게 아니라 action을 생성하는 함수를 만들어 주는거니까 createActionCreator가 더 맞겠지만 좀 간장공장공장장 같아서 createAction으로 명명되었다.

물론! .toString() 함수나 .type property를 사용해서 action type을 문자열로 얻을 수 있다.

const increment = createAction('INCREMENT')
console.log(increment.toString())
// "INCREMENT"
console.log(increment.type)
// "INCREMENT"

createAction함수를 써서 다시 Counter App을 작성해보자.

const increment = createAction('INCREMENT')
const decrement = createAction('DECREMENT')
function counterReducer(state = 0, action) {
  switch (action.type) {
    case increment.type:
      return state + 1
    case decrement.type:
      return state - 1
    default:
      return state
  }
}
const store = configureStore({
  reducer: counterReducer
});
var store = Redux.createStore(counterReducer);
document.getElementById('incrementBtn').addEventListener('click', function(){
  store.dispatch(increment());
});

Good~

Introducing: createReducer

const increment = createAction('INCREMENT')
const decrement = createAction('DECREMENT')
const counter = createReducer(0, {
  [increment.type]: state => state + 1,
  [decrement.type]: state => state - 1
})

코드가 많이 짧아졌고, 어떤 점에서 switch문을 대체했는지도 알아보기 쉽다. 그리고, createReducer안에서 .toString()을 호출해주기 때문에 아래와 같이 작성해도 된다.

const counter = createReducer(0, {
  [increment]: state => state + 1,
  [decrement]: state => state - 1
})

Introducing: createSlice

지금까지 작성한 코드를 살펴보자.

const increment = createAction('INCREMENT')
const decrement = createAction('DECREMENT')
const counter = createReducer(0, {
  [increment]: state => state + 1,
  [decrement]: state => state - 1
})
const store = configureStore({
  reducer: counter
})
document.getElementById('increment').addEventListener('click', () => {
  store.dispatch(increment())
})

나쁘지 않다. 코드가 많이 짧아졌다. 하지만, 한걸음 더 나아가서 aciton과 reducer를 합칠 수 있다. 둘은 counter에서 쓰인다는 공통점이 있기때문에 코드를 읽을 때도 (문맥상?) 더 편할것이다.

const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: {
    increment: state => state + 1,
    decrement: state => state - 1
  }
})
;
const store = configureStore({
  reducer: counterSlice.reducer
})
;
document.getElementById('incrementBtn').addEventListener('click', () => {
  store.dispatch(counterSlice.actions.increment())
});

만약에 counterSlice.actions.increment()라고 길게 쓰는게 불편하면 ES6의 destructuring syntax 문법을 사용하면 된다.

const { actions, reducer } = counterSlice
const { increment, decrement } = actions

요약

  • configureStore : store를 생성하는 함수인데, 안에서 Redux DevTools Extension과 몇가지 유용한 middleware를 설정해 놓았다.
  • createAction : action을 만들어주는 함수를 만들어주는 함수이다.
  • createReducer : switch문을 안써도 reducer를 만들어준다.
  • createSlice : 이게 진국. action과 reducer를 묶어준다. 이 묶음을 slice라고 부르는듯.

다음글 : https://develoger.local:80/redux-toolkit-intermediate-tutorial/

Add Comment