typescript + react + redux toolkit counter

YOUNGJOO-YOON·2021년 8월 22일
0

TS+REACT

목록 보기
5/10

TS + REACT + RTK COUNTER

redux는 역시 counter를 만들어 봐야 감이 잡힌다.
최신 RTK의 방식은 어떠한지 업데이트 할 겸 따라가보자.

참고자료
https://redux-toolkit.js.org/tutorials/typescript
https://codesandbox.io/s/qo6l3?file=/src/App.tsx


내가 만든 TS React RTK Counter

RTK에서 소개하는 방식을 토대로 작성하였다.

개선점

  1. 기존의 store 내부의 state를 선택하던 select 방식을 개선해 callback 함수를 통해 더 간편하게 선택 가능
    (자체 hook을 만들어야 함)

store file tree


store.tsx

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을 유추하기 위해 사용


hooks.ts

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을 특정한다.


counterReducer.tsx

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는 기존과 거의 동일하다.


counter.tsx

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으로 읽어와준다.

profile
이 블로그의 글은 제 생각을 정리한 글과 인터넷 어딘가에서 배운 것을 정리한 글입니다. 출처는 되도록 남기도록 하겠습니다. 수정 및 건의 오류 등이 있으면 언제든지 댓글 부탁드립니다.

0개의 댓글