redux는 역시 counter를 만들어 봐야 감이 잡힌다.
최신 RTK의 방식은 어떠한지 업데이트 할 겸 따라가보자.
참고자료
https://redux-toolkit.js.org/tutorials/typescript
https://codesandbox.io/s/qo6l3?file=/src/App.tsx
내가 만든 TS React RTK Counter
RTK에서 소개하는 방식을 토대로 작성하였다.
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counterReducer";
export const store = configureStore({
reducer:{
counters:counterReducer
},devTools:true
})
export type RootState = ReturnType<typeof store.getState> // custom hook
export type AppDispatch=typeof store.dispatch
export type RootState = ReturnType<typeof store.getState>
https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype
TS의 ReturnType을 사용한다.
type을 export 한다.
root state의 type을 유추하기 위해 사용
export type AppDispatch=typeof store.dispatch
dispatch 되는 type을 유추하기 위해 사용
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from './store';
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
useAppDispatch
에서
AppDispatch = typeof store.dispatch
dispatch 되는 state의 type을 특정한다.
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import type { RootState } from './store'
interface CounterState{
value:number
}
const initialState:CounterState={
value:0,
}
export const counterSlice = createSlice({
name:'counter',
initialState,
reducers:{
increment:(state)=>{
console.log('increment')
state.value +=1
},
decrement:(state)=>{
console.log('decrement')
state.value -=1
},
incrementByAmount:(state,action:PayloadAction<number>)=>{
state.value += action.payload
},
}
})
export const { increment, decrement, incrementByAmount} = counterSlice.actions
export const selectValue = (state:RootState) =>state.counters.value;
export default counterSlice.reducer
slice는 기존과 거의 동일하다.
import React, { useState } from 'react'
import { useAppSelector, useAppDispatch } from './store/hooks'
import { decrement, increment, incrementByAmount } from './store/counterReducer';
export function Counter() {
const count = useAppSelector(state=>state.counters.value);
const dispatch = useAppDispatch()
return(
<div>
<h1>{count}</h1>
<button onClick={()=>dispatch(increment())}>increment</button>
<button onClick={()=>dispatch(decrement())}>decrement</button>
<button onClick={()=>dispatch(incrementByAmount(10))}>10 increment</button>
</div>
)
}
변수 count, dispatch
를 보면 기존과는 다르게 custom hook을 사용한다
useAppSelector
는
const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
이다. 기존의 useSelector의 type을 지정해준다고 보면 된다.
변수 dispatch
는 useAppDispatch()를 사용한다.
useAppDispatch = () => useDispatch<AppDispatch>();
type AppDispatch=typeof store.dispatch
type AppDispatch는 store에서 dispatch 되는 state의 type을 generic으로 읽어와준다.