이전 포스팅 글
- 2022.10.25 - [개발 공부 시리즈/Redux-ToolKit] - [RTK] Typescript todoList 만들기 - (1)
- 2022.10.26 - [개발 공부 시리즈/Redux-ToolKit] - [RTK] Typescript todoList 만들기 - (2) 기본적인 디자인하기
- 2022.10.27 - [개발 공부 시리즈/Redux-ToolKit] - [RTK] Typescript todoList 만들기 - (3) 삭제 기능 만들기
[RTK] Typescript todoList 만들기 - (4) 컴포넌트 분리하기
이번 포스팅에서는 RTK TODO APP의 컴포넌트 분리를 해보겠다.
컴포넌트 분리 기준은 개발자마다 각각 달라서 자신이 편한 대로 쓰는 게 가장 좋기는 하지만,
같이 개발하는 사람과 어떻게 분리할 것인지 계획하고, 아니면 많은 사람들의 코드를 보고 따라 하는 것이 가장 좋기는 하다.
1. 기능 단위 컴포넌트 분리
RTK 공식 홈페이지에서 제공하는 CRA(Create-react-app) 템플릿에서는 다음과 같은 폴더 구조로 되어있다.
공식 템플릿 버전에서는 app/ 폴더에는 hook과 store 가 존재하고 있다.
features/ 라는 폴더 안에는 기능 단위로 컴포넌트, 스타일, Redux 등의 코드를 같이 넣는 것을 권장한다.
무엇보다 개인과 협업하는 사람들의 의견을 조율해야 하지만 나는 RTK에서 권장하는 방식으로 구현해야겠다.
2. todoList.tsx 컴포넌트 생성 및 module.css, App.tsx 변경
features/todos 폴더에 todoList.tsx 컴포넌트를 생성하고, 현재 App.tsx의 코드를 가져온다.
todoList.tsx
import React, {useState} from 'react'
import { AppDispatch, RootState } from "../../app/store";
import { useSelector, useDispatch } from "react-redux";
import { addTodo, deleteTodo } from "./todoSlice";
//meterial Ui
import CssBaseline from "@mui/material/CssBaseline";
import Container from "@mui/material/Container";
import Box from "@mui/material/Box";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import List from "@mui/material/List";
import { ListItem } from "@mui/material";
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
//css modules import
import styles from './Todo.module.css'
function TodoList() {
const todoList = useSelector((state: RootState) => state.todos);
const dispatch = useDispatch<AppDispatch>();
// console.log(dispatch);
let [txt, setTxt] = useState("");
return (
<CssBaseline>
<Container fixed>
<Box sx={{ height: "100vh" }}>
<h1 className={styles.center}>Todo List</h1>
<div className={styles.center}>
<TextField
type="text"
onChange={(e) => setTxt(e.target.value)}
id="standard-basic"
label="todo Input"
variant="standard"
value={txt}
></TextField>
<Button
style={{ marginTop: "10px", marginLeft: "10px" }}
variant="outlined"
onClick={(e) => {
dispatch(addTodo(txt));
setTxt('')
console.log(e);
}}
>
추가
</Button>
</div>
<div className={styles.center}>
<h3>할일 내용</h3>
<List
dense
sx={{
margin: "0 auto",
width: "100%",
maxWidth: 360,
bgcolor: "background.paper",
}}
>
{todoList.map((item) => (
<Card className={styles.card} style={{ marginTop: "20px" }}>
<CardContent>
<ListItem
style={{ justifyContent: "space-between" }}
disableGutters
key={item.id}
// dispatch 추가
onClick={() => {
dispatch(deleteTodo(item.id));
}}
>
{item.text}{" "}
<DeleteOutlineIcon style={{ float: "right" , cursor: 'pointer' }} />
</ListItem>
</CardContent>
</Card>
))}
</List>
</div>
</Box>
</Container>
</CssBaseline>
)
}
export default TodoList;
App.tsx 의 코드를 가져와서 위의 예제와 같이 경로를 변경하였다.
기존의 App.module.css 의 파일도 TodoList.module.css를 생성하여 새로운 경로를 붙여주었다.
TodoList.module.css
.wrapper {
background-color: blanchedalmond;
}
.center {
text-align: center;
}
.margin-auto {
margin : 0 auto
}
.card:hover {
background-color: aliceblue;
}
App.tsx 파일은 다음과 같이 변경하였다.
features/todos/TodoList.tsx를 import 해주었다.
App.tsx
import React from "react";
import ToodList from './features/todos/TodoList';
function App() {
return (
<>
<ToodList />
</>
);
}
export default App;
3. TodoItem.tsx 생성
todoList의 해당 카드 각각의 할 일 요소가 되는 항목도 TodoItem.tsx의 컴포넌트 파일로 분리해주겠다.
TodoItem.tsx
import React from "react";
import { AppDispatch } from "../../app/store";
import { useDispatch } from "react-redux";
import { deleteTodo } from "./todoSlice";
import { ListItem } from "@mui/material";
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import styles from './TodoItem.module.css';
interface Todo {
id : string;
text : string;
completed : boolean
}
function TodoItem({todo } : {todo: Todo}) {
const dispatch = useDispatch<AppDispatch>();
return (
<>
<Card className={styles.card} style={{ marginTop: "20px" }}>
<CardContent>
<ListItem
style={{ justifyContent: "space-between" }}
disableGutters
key={todo.id}
// dispatch 추가
onClick={() => {
dispatch(deleteTodo(todo.id));
}}
>
{todo.text}{" "}
<DeleteOutlineIcon
style={{ float: "right", cursor: "pointer" }}
/>
</ListItem>
</CardContent>
</Card>
</>
);
}
export default TodoItem;
사실 여기서 엄청 헤맸다.
TodoList와 TodoItem의 todo의 값을 props로 넘겨 주려 했지만, 타입 스크립트 형태에서 어떻게 사용할지 몰라서 계속 오류가 났었다.
interface Todo {
id : string;
text : string;
completed : boolean
}
function TodoItem({todo } : {todo: Todo}) {
..///
interface로 store.ts 에 있는 Todo객체와 똑같이 설정해주고, 아래 props 받는 방식이 원래는 ({props}) 로 사용하였는데 타입을 어떻게 붙일지 몰라서 한참을 헤맸다.
위와 같이 구현하니 잘 작동되었다.
TodoItem.module.css 도 새로 생성해주었다.
TodoItem.module.css
.card:hover {
background-color: aliceblue;
}
TodoList.tsx 에는 TodoItem.tsx를 추가하고, TodoItem에 props로 todo들을 내보내 준다.
TodoList.tsx
//todoItem 컴포넌트 추가
import TodoItem from './TodoItem'
//... 일부 코드 발췌
<div className={styles.center}>
<h3>할일 내용</h3>
<List
dense
sx={{
margin: "0 auto",
width: "100%",
maxWidth: 360,
bgcolor: "background.paper",
}}
>
{todoList.map((item) => (
<TodoItem todo={item}/>
))}
</List>
</div>
///...
4. 완성된 폴더구조
전체적인 디렉터리 구조는 이러하다. Todo관련 기능을 담당하는 것을 fetures/todos 폴더에 몰아서 넣었다.
타입 스크립트로 react를 사용하는 것이 너무 미숙하여 더 많은 공부를 해야겠다.
간단한 props를 넘기는 것조차 사용하기가 어려운 느낌이 있다.
직접 부딪히며, 더 많이 알아가야지!!
전체 적인 코드는 github 에도 올려놓았다.
https://github.com/ijw9209/rtk-ts-todo-app
'개발 공부 시리즈 > Redux-ToolKit' 카테고리의 다른 글
[RTK] Typescript todoList 만들기 (5) - eslint, prettier 적용해보기- 2 (0) | 2022.11.01 |
---|---|
[RTK] Typescript todoList 만들기 (5) - eslint, prettier 적용해보기- 1 (0) | 2022.11.01 |
[RTK] Typescript todoList 만들기 - (3) 삭제 기능 만들기 (2) | 2022.10.27 |
[RTK] Typescript todoList 만들기 - (2) 기본적인 디자인하기 (0) | 2022.10.26 |
[RTK] Typescript todoList 만들기 - (1) (0) | 2022.10.25 |
댓글