[RTK] Typescript todoList 만들기
Redux-Toolkit과 Typescirpt를 사용한 TodoList를 정리하며, 만들어 보는 시간을 가져보겠다.
1. 프로젝트 설치
typescript 템플릿을 이용하여 다운로드하도록 하겠다.
자신이 원하는 디렉터리로 cmd 창을 열고 다음과 같은 명령어를 입력하면 된다.
npx create-react-app rtk-todo-list --template typescript
설치가 완료되면 만들어진 디렉토리로 이동하여 vsCode로 프로젝트를 연다.
자세한 Redux-Toolkit 설치방법은 이 포스팅을 참고하면 된다.
2022.10.03 - [개발 공부 시리즈/Redux-ToolKit] - [React] Redux-Toolkit 초기 설치
2. 프로젝트 실행해보기
vsCode 터미널 창에서 => npm start 명령어로 실행해보면 다음과 같이 구동되는 것을 확인할 수 있다.
3. App.tsx 수정하기
프로젝트의 App.tsx의 내용을 지우고, 다음과 같이 작성한다.
import React from 'react';
import './App.css';
function App() {
return (
<>
<h1>할일 관리</h1>
</>
);
}
export default App;
기존의 React 로고가 나오는 코드들을 지우고, 할 일 관리에 대한 내용을 작성할 것이다.
4. 필요한 패키지 설치하기
- redux toolkit과 react-redux를 다운로드한다.
npm install @reduxjs/toolkit react-redux
- 디자인에 사용할 material UI를 다운로드한다.
npm install @mui/material @emotion/react @emotion/styled
https://mui.com/material-ui/getting-started/installation/
- uuid를 사용하여 고유 아이디를 생성한다. uuid의 라이브러리를 다운로드한다.
npm install uuid @types/uuid
https://www.npmjs.com/package/uuid
5. 폴더 구조 만들기
src 폴더 하위에 app 폴더와 features 폴더를 만든다.
app 폴더는 Redux의 store나 hook 등의 내용이 들어가는 폴더이고,
features 폴더는 하위에 slice 및 component가 들어갈 폴더이다.
6. store.ts , hook.ts 작성하기
RTK 공식 문서를 참고하여 app/store.ts 와 app/hook.ts를 작성해준다.
app/store.ts
//store.ts
import { configureStore } from '@reduxjs/toolkit'
import todoReducer from '../features/todos/todoSlice'
// ...
export const store = configureStore({
reducer: {
todos : todoReducer,
}
})
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
파일 이름 그대로 store는 저장되는 공간이다.
app/hook.ts
//hook.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
hook.ts는 RootState 및 AppDispatch의 타입을 가져올 수 있다.
7. Slice 작성
features/todos/todoSlice.ts
import { createSlice , PayloadAction } from '@reduxjs/toolkit'
import type { RootState } from '../../app/store'
import { v4 as uuidv4 } from 'uuid';
// Define a type for the slice state
interface Todo {
id : string;
text : string;
completed : boolean
}
// Define the initial state using that type
const initialState: Todo[] = [
{
id : uuidv4(),
text : '테스트',
completed : false
}
];
export const todoSlice = createSlice({
name: 'todos',
// `createSlice` will infer the state type from the `initialState` argument
initialState,
reducers: {
//할일 추가
addTodo: (state , action: PayloadAction<string>) => {
// const { text } = action.payload;
state.push({id : uuidv4(), text : action.payload, completed : false });
},
},
})
export const { addTodo } = todoSlice.actions
// Other code such as selectors can use the imported `RootState` type
export const selectTodos = (state: RootState) => state.todos
export default todoSlice.reducer
어기서 타입 스크립트 사용으로 인해 작성방법을 굉장히 헤매었다.
설명하자면 Todo라는 객체의 타입을 먼저 설정해주고, 초기값을 initialState로 선언해준다.
CreateSlice는 사용할 reducers를 정의하는 공간이다. 일단 할 일 추가를 추가하였다 action.paload에는 dispatch로 사용자가 보내는 값이 담아서 들어오게 된다.
할일 추가 기능에는 사용자가 입력한 텍스트가 들어오게 되며, id 값은 uuid()로 난수가 생성되고, completed(할 일 완료할 때 true로 바뀐다.) false를 기본값으로 설정해 주었다.
8. Provider 선언
루트 경로에 있는 index.tsx의 Provider를 선언하고 store를 연결해준다.
index.tsx
//index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { store } from './app/store'
import { Provider } from 'react-redux'
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>,
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
Provider 연결을 깜빡하고 계속 오류가 어디서 났는지 찾고 있었다...
하지만 오류 코드를 제대로 보니 Provider 문제라고 떡하니 써져있었는데, 오류코드를 잘 봐야 하는 중요성에 대해 다시 한번 깨닫게 된다. store를 연결해준다.
9. App.tsx 작성
App.tsx를 다음과 같이 변경해준다.
App.tsx
import React,{ useState } from 'react';
import { AppDispatch, RootState } from './app/store'
import { useSelector, useDispatch } from 'react-redux'
import { addTodo } from './features/todos/todoSlice';
function App() {
const todoList = useSelector((state: RootState) => state.todos)
const dispatch = useDispatch<AppDispatch>()
console.log(dispatch)
let [ txt , setTxt ] = useState('');
return (
<>
<h1>할일 관리</h1>
<div>
<input
type="text"
onChange={(e) => setTxt(e.target.value)}
></input>
<button
onClick={() => {
dispatch(addTodo(txt));
}}
>추가</button>
</div>
<div>
<h3>할일 내용</h3>
<>
{todoList.map((item) =>(
<p key={item.id}>{item.text}</p>
))}
</>
</div>
</>
);
}
export default App;
일단 기능 먼저 구현하도록 하였다.
설명하자면 useSelector로 현재 전역 state에 있는 todos를 가져와서 보여주게 되며,
dispatch함수를 이용해 추가 버튼을 눌렀을 때 할 일이 추가되도록 만들었다.
나는 여기서 한참 동안 헤매었다.
dispatch 함수에서 자동으로 reducer를 매칭 해주는지 알고 addTodo함수를 계속 찾을 수 없다길래 설정에 오류사항이 있는 줄 알았다.
하지만 알고 보니 Slice를 import 하여 사용하는 것이었다..ㅠ
그래도 그 덕분에 redux-toolkit에 대한 이해도는 많이 올라간 것 같다.
현재까지 구현 내용
매번 다른 사람의 코드를 따라서 치다가 내가 이번엔 직접 부딪히려고 구현하였는데, 생각보다 시간이 더 오래 걸리게 되었지만, 한두 번 계속 헤매는 것이 내 실력에 정말 많은 도움이 된다는 것을 다시 한번 깨닫는다.
늦은 시간까지 하느라 멈출까도 생각하였지만, 참고 계속하려고 한 것이 잘한 것 같다.
디자인 및 삭제 기능은 다음 포스팅으로 이어가도록 하겠다.
'개발 공부 시리즈 > Redux-ToolKit' 카테고리의 다른 글
[RTK] Typescript todoList 만들기 - (4) 컴포넌트 분리하기 (0) | 2022.10.28 |
---|---|
[RTK] Typescript todoList 만들기 - (3) 삭제 기능 만들기 (2) | 2022.10.27 |
[RTK] Typescript todoList 만들기 - (2) 기본적인 디자인하기 (0) | 2022.10.26 |
[React] Redux-Toolkit TypeScript Quick Start (0) | 2022.10.20 |
[React] Redux-Toolkit 초기설치 (1) | 2022.10.03 |
댓글