[React&TS] 0. Todo 개요 및 Redux세팅

파이·2021년 12월 9일
1

개요

이번에 타입스크립트를 배웠습니다.
항상 새로운 언어나 도구를 배울때 마다 TodoList를 만들어보는 편인데, 다행히 그냥 Todo를 만드는데에는 어렵지 않았습니다. 근데 간단한 기능 몇 가지만 추가하려고 해도 오류가 많더라구요. 때문에 제작 이후 복기를 위해 포스트를 적어봅니다.

사용된 총 기술은 다음과 같습니다

  • React.js
  • TypeScript
  • Sass (Scss)
  • 'openweathermap' 기상정보 REST API
  • 달력을 위한 'Full Calendar' Module

0. React + TypeScript Setup

우선 기본 설치를 해주겠습니다.

npx create-react-app [프로젝트명] --template typescript

이렇게 뒤에 --template typescript 만 붙여주면 끝입니다.
다만 앞으로 모듈들을 추가로 설치하면 새롭게 설치해줘야 하는데,

npm i react-redux @types/react-redux

이런식으로 뒤에 @types/모듈명 을 붙여 똑같이 추가해주면 됩니다.

기존 프로젝트를 TS로 리팩토링한다면?

이 때는 npx CRA를 활용하는게 아니므로, types들을 찾아서 다 재설치해주면 됩니다.
만약 모듈이 하나도 안 깔려있고 CRA만 사용된 상태라면

npm i typescript @types/node @types/react @types/react-dom @types/jest

이렇게 typescript와 함께 기본적으로 설치되는 4개의 모듈들의 각각 타입들을 따로 찾아줘야 합니다.

결국 이렇게 주루룩 타입들이 잘 설치된걸 확인 할 수 있습니다. 참 쉽죠?

! React가 아닌 바닐라 JS에서 설치방법은 다릅니다.



1. Redux 설정

중간에 useState => Redux로 리팩토링했는데, 여기서 정말 어려웠습니다.
기존에 쓰던 막 쓰는 Redux가 아닌, 제대로 폴더구조를 짜다보니 복잡하더라구요. 아무튼

이런식으로 폴더 구조를 만들었습니다.



todo-reducer.tsx

여기서 정말 헤멨습니다. 기본적으로 action함수들을 reducer 부분에서 관리하는건 처음이었거든요. 아무튼 이렇게 쓰는게 일반적인 것 같은데,
특히나 TS에선 action함수들의 Type까지 지정해줘야해서, 이렇게 하는게 거의 필수되는 것 같습니다.
우선,

// addTodo함수
export const addTodo = (content :string) => ({
  type: 'addTodo',
  data: { id: Date.now(), content: content, checked: false }
});

// input todo 사용시
dispatch(addTodo(inputMemo))

이런식으로 미리 addTodo함수를 지정해서 export 해 줍니다. addTodo하는 부분에선 import해서 사용하면 되고, 오류가 날 시, todo-reducer에서 한 번에 수정이 가능하니, 유지보수 측면에서 더 용이합니다.
추후 사용시에는 dispatch() 안에 해당 함수를 넣어서 사용합니다.
그리고 reducer switch 문 안에 들어갈 action 함수의 타입을 지정해줘야 하는데,

type TypeAction =
    { type: 'addTodo';  data: ITodo }
  | { type: 'deleteTodo';  data: number }
  | { type: 'checkTodo';  data: number }

저는 이런식으로 사용했습니다. Generic과 typeof를 사용하여 좀 더 간단하게 구현이 가능한 것 같지만, 저는 아직은 이게 더 알아보기 쉽더라구요.

그리고 마지막으로 reducer는

const todoReducer = ( state: ITodo[] = loadMemo, action: TypeAction): ITodo[] => {
  switch (action.type) {
    
    case 'addTodo': 
      let newData: ITodo[] = [...state, action.data]
      saveAndload(newData)
      return newData
    

위에서 지정해놓은 Todo 의 interface와 action타입을 적극적으로 사용해줬습니다.
함수 인자는 지정해야한다 는 원칙이 일반적인 것 같은데, 다 작성하고 보니 이해가 되는 문법입니다.



redux-index.tsx

rootreducer를 보내는 파일입니다.
보통 index로 파일명을 정하는것 같은데, 기존 index와 헷갈릴까봐 redux까지 붙여줬습니다.
아무튼 코드는 간결합니다.

import { combineReducers } from 'redux';
import todoReducer from './modules/todo-reducer';

const rootReducer = combineReducers({
  todoReducer
});

// 루트 리듀서를 내보내주세요.
export default rootReducer;

// 루트 리듀서의 반환값를 유추해줍니다
// 추후 이 타입을 컨테이너 컴포넌트에서 불러와서 사용해야 하므로 내보내줍니다.
export type RootState = ReturnType<typeof rootReducer>;

사실 reducer파일이 하나뿐이라, combineReducers를 쓸 필요는 없지만 환경은 중요하니까요.
일반적인 rootreducer랑 거의 똑같지만 다른 부분이 있다면 마지막줄입니다.
RootReducer을 ReturnType 을 통해 타입을 유추해준 문법입니다.
Generic이라 아직 익숙하지 않지만, 이제 대충 이해는 되는군요.\



...

아무튼 기본 세팅은 이정도입니다. 처음 세팅할 때는 굉장히 스트레스를 받았는데, 이렇게 보니 꽤 간결한 것 같네요.
아무튼 한번에 다 쓰면 보기 어려우니, 문서를 분리해서 써야될 것 같습니다.

profile
기록

0개의 댓글