Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3주차] 주효정 미션 제출합니다. #15

Open
wants to merge 40 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
a96be62
style: add container box
jhj2713 Mar 20, 2022
13dce4a
feat: add addTodoItem function
jhj2713 Mar 21, 2022
3426754
feat: add todo to done toggle
jhj2713 Mar 21, 2022
730aa49
feat: add done to todo toggle
jhj2713 Mar 21, 2022
1dfcca7
feat: add delete function
jhj2713 Mar 21, 2022
72e52c3
feat: add saveLocalStorage function
jhj2713 Mar 21, 2022
2fd507f
style: change ui
jhj2713 Mar 21, 2022
2508a13
fix: change to functional component
jhj2713 Mar 21, 2022
c8638ea
style: change UI and add font style
jhj2713 Mar 21, 2022
66843a2
refactor: add list component
jhj2713 Mar 21, 2022
c0530ec
refactor: add input component
jhj2713 Mar 21, 2022
4742cf7
refactor: add styled components
jhj2713 Mar 21, 2022
e78f1ab
refactor: delete doneList component
jhj2713 Mar 21, 2022
73a2035
refactor: add styled components in TodoList
jhj2713 Mar 21, 2022
57c76d1
style: change UI
jhj2713 Mar 21, 2022
c6f5f52
refactor: add useCallback function
jhj2713 Mar 21, 2022
f795be3
style: change title and icon
jhj2713 Mar 21, 2022
5690951
style: change UI
jhj2713 Mar 24, 2022
f30b495
style: change UI
jhj2713 Mar 24, 2022
6e6256c
refactor: usage of props in styled-components
jhj2713 Mar 24, 2022
22d1f3d
refactor: change InputText location
jhj2713 Mar 24, 2022
8f38c5e
fix: dependency warning
jhj2713 Mar 25, 2022
a971121
refactor: add globalStyle
jhj2713 Mar 25, 2022
3ba7e60
refactor: change localStorage load location
jhj2713 Mar 26, 2022
6edb893
refactor: change Styled-components location
jhj2713 Mar 26, 2022
9b3b9e9
refactor: add todoItem
jhj2713 Mar 28, 2022
3d0c45a
refactor: refactor typescript
jhj2713 Mar 28, 2022
f813526
refactor: add inputType
jhj2713 Mar 28, 2022
ed12088
refactor: add custom hooks
jhj2713 Mar 28, 2022
5404fc6
refactor: interface refactoring
jhj2713 Mar 28, 2022
a1514c9
refacor: add context
jhj2713 Mar 29, 2022
8eb76cc
refactor: remove memo
jhj2713 Mar 31, 2022
6c10362
refactor: change title location
jhj2713 Mar 31, 2022
0aaf39f
refactor: add customInput hook
jhj2713 Mar 31, 2022
4024ce2
refactor: add reducer
jhj2713 Mar 31, 2022
90f7462
chore: add type
jhj2713 Mar 31, 2022
c950615
chore: add comment
jhj2713 Mar 31, 2022
69ad840
refactor: change some types and rename tag
jhj2713 Apr 2, 2022
dbec7e7
refactor: add useTodo hook
jhj2713 Apr 2, 2022
69f52da
refactor: change function name
jhj2713 Apr 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16,591 changes: 16,547 additions & 44 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.4.1",
"@types/node": "^17.0.23",
"@types/react": "^17.0.43",
"@types/react-dom": "^17.0.14",
"@types/styled-components": "^5.1.24",
Comment on lines +9 to +13

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

타입 라이브러리의 경우 dev-dependencies에 추가해주면 배포 때 번들 사이즈를 줄일 수 있을 것 같아요!

[https://ingorae.tistory.com/1754](참고 링크)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 처음 안 사실이네요! 앞으로 참고해서 사용하겠습니다!

"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "5.0.0",
"styled-components": "^5.3.3",
"typescript": "^4.6.3",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
Binary file added public/bin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/favicon.ico
Binary file not shown.
6 changes: 5 additions & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<link
href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&display=swap"
rel="stylesheet"
/>
<title>투두리스트</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
10 changes: 0 additions & 10 deletions src/App.js

This file was deleted.

58 changes: 58 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useEffect, useCallback, useContext } from "react";
import styled from "styled-components";
import { TodoInputForm, TodoList, DoneList } from "components";
import { TodoContext } from "contexts";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contexts에서 index.tsx에서 따로 export 해온게 이부분에서 더 깔끔하게 보이기 위해서라고 이해하면 될까요?? 혹시 다른 이유가 또 있을까요??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

특별한 이유는 없고 한 폴더에서 여러 컴포넌트를 import 할 때 한 줄로 깔끔하게 import하기 위해서 자주 사용했습니다..

import { ITodoItem } from "interface";

const App = () => {
const { todoList, doneList } = useContext(TodoContext);

// save to localStorage
const _saveLocalStorage = useCallback(
(type: string, list: Array<ITodoItem>): void => {
localStorage.setItem(type, JSON.stringify(list));
},
[],
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 Hooks 내부에 정의할 필요는 따로 없을 것 같네요 ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇네요! 밖으로 뺄 생각을 못했네요. 감사합니다!!


// list가 변할 때마다 localStorage에 list 저장
useEffect(() => {
_saveLocalStorage("todoList", todoList);
}, [todoList, _saveLocalStorage]);
useEffect(() => {
_saveLocalStorage("doneList", doneList);
}, [doneList, _saveLocalStorage]);

return (
<Container>
<Box>
<TitleContents>
<TodoTitle>📝 투두리스트</TodoTitle>
</TitleContents>
<TodoInputForm />
<TodoList />
<DoneList />
</Box>
</Container>
);
};

const TitleContents = styled.section``;
const TodoTitle = styled.h2`
padding-left: 20px;
`;
const Container = styled.div`
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사람마다 다른데, 최상위 컴포넌트는 Wrapper로 이름 짓는 경우가 많더라구요 ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어쩐지 네이밍이 마음에 안 들더라구요.. 알려주셔서 감사합니다!

const Box = styled.main`
width: 350px;
height: 600px;
background-color: white;
border-radius: 20px;
box-shadow: 1px 1px 30px grey;
`;

export default App;
54 changes: 54 additions & 0 deletions src/components/DoneList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useContext, useCallback } from "react";
import styled from "styled-components";
import TodoItem from "./TodoItem";
import { TodoContext } from "contexts";

const DoneList = () => {
const { doneList, dispatch } = useContext(TodoContext);

// todo item 추가
const _addTodoList = useCallback(
(todo: string): void => {
dispatch({
type: "ADD_TODO",
todo: { text: todo },
});
},
[dispatch],
);

// done item 삭제
const _deleteDoneList = useCallback(
(idx: number): void => {
dispatch({
type: "DELETE_DONE",
idx,
});
},
[dispatch],
);

return (
<TodoContents>
<h3>DONE ({doneList.length})</h3>
<ul>
{doneList.map(({ text }, idx) => (
<TodoItem
key={idx}
type="done"
todo={text}
idx={idx}
deleteCurrentList={_deleteDoneList}
addToggleList={_addTodoList}
/>
))}
</ul>
</TodoContents>
);
};

const TodoContents = styled.section`
padding: 0 20px;
`;

export default DoneList;
70 changes: 70 additions & 0 deletions src/components/TodoInputForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useCallback, useContext } from "react";
import styled from "styled-components";
import { TodoContext } from "contexts";
import { useInput } from "hooks";

const TodoInputForm = () => {
const { dispatch } = useContext(TodoContext);
const { text, _handleTextChange, _resetText } = useInput("");

// todo item 추가
const _addTodoItem = useCallback(
(e: React.FormEvent): void => {
e.preventDefault();

if (text.trim()) {
// list에 todo item 추가
dispatch({
type: "ADD_TODO",
todo: { text },
});
}
_resetText();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 앞서 말씀드린 useTodo 훅에 넣어도 될 것 같네요!

const { addTodo } = useTodo()
const handleTodoInputChange = (event: React.FormEvent) => {
    addTodo({text: event.target.value})
}

// ... addTodo는 useTodo내에서 구현

이렇게 하면 todoInputForm의 이벤트 처리 로직과 todo 상태 변경 로직의 분리를 달성할 수 있습니다.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 커스텀 훅에 적용해보도록 하겠습니다~!

},
[text, _resetText, dispatch],
);

return (
<TodoInputItems onSubmit={_addTodoItem}>
<TodoInput
placeholder="할 일을 입력하세요"
value={text}
onChange={_handleTextChange}
/>
<TodoInputBtn type="submit">+</TodoInputBtn>
</TodoInputItems>
);
};

const TodoInputItems = styled.form`
display: flex;
justify-content: center;
align-items: center;
padding-bottom: 15px;
border-bottom: 1px solid lightgrey;
`;
const TodoInput = styled.input`
border: 1px solid lightgrey;
border-radius: 10px;
padding: 15px;
width: 230px;
:focus {
outline: none;
transition: 0.2s;
box-shadow: 0px 0px 5px lightgrey;
}
`;
const TodoInputBtn = styled.button`
background: none;
border: none;
font-size: 30px;
margin-left: 10px;
cursor: pointer;
border-radius: 30px;
:hover {
color: grey;
transition: 0.2s;
}
`;

export default TodoInputForm;
67 changes: 67 additions & 0 deletions src/components/TodoItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useCallback } from "react";
import styled, { css } from "styled-components";
import { ITodoItemProps } from "interface";

const TodoItem = ({
type,
todo,
idx,
deleteCurrentList,
addToggleList,
}: ITodoItemProps) => {
Comment on lines +5 to +11

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const TodoItem = ({
type,
todo,
idx,
deleteCurrentList,
addToggleList,
}: ITodoItemProps) => {
const TodoItem = ({
type,
todo,
idx,
deleteCurrentList,
addToggleList,
}: ITodoItemProps): React.FC<ITodoItemProps> => {

보통은 이런 식으로 직접 컴포넌트를 타이핑해준답니다.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하 넵 저걸 빼먹었네요!

// todo <-> done
const _toggleTodo = useCallback((): void => {
// toggle된 리스트에 item 추가
addToggleList(todo);

// 현재 리스트에서 item 삭제
deleteCurrentList(idx);
}, [addToggleList, todo, deleteCurrentList, idx]);

// delete item
const _deleteTodo = useCallback((): void => {
deleteCurrentList(idx);
}, [idx, deleteCurrentList]);

return (
<ListItem>
<ListToggleItem onClick={_toggleTodo}>
<span>{type === "todo" ? "□" : "✔"}</span>
<ListItemText type={type}>{todo}</ListItemText>
</ListToggleItem>
<TodoDeleteBtn src="bin.png" alt="delete-btn" onClick={_deleteTodo} />
</ListItem>
);
};

const TodoDeleteBtn = styled.img`
width: 14px;
padding-left: 5px;
cursor: pointer;
opacity: 0;
`;
const ListItem = styled.li`
margin-bottom: 13px;
:hover {
${TodoDeleteBtn} {
opacity: 1;
transition: 0.1s;
}
Comment on lines +46 to +49

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

styled-components의 고급 기능을 잘 활용하셨네요!

Comment on lines +43 to +49
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hover 안에 다른 요소를 넣을 수 도 있군요..! 앞으로 저도 자주 쓰게 될 것 같습니다.

}
`;
const ListToggleItem = styled.section`
display: inline;
cursor: pointer;
`;
const ListItemText = styled.span<{ type: "todo" | "done" }>`
font-size: 15px;
padding-left: 5px;
${({ type }) =>
type === "done" &&
css`
text-decoration: line-through;
color: lightgrey;
`}
`;

export default React.memo(TodoItem);
55 changes: 55 additions & 0 deletions src/components/TodoList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useContext, useCallback } from "react";
import styled from "styled-components";
import TodoItem from "./TodoItem";
import { TodoContext } from "contexts";

const TodoList = () => {
const { todoList, dispatch } = useContext(TodoContext);

// done item 추가
const _addDoneList = useCallback(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

함수 네이밍에 _(언더바)가 어떤 의미를 갖는지 궁금합니다!!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

처음에는 변수명과 함수를 구분하기 위해 사용했던게 습관이 되었던 것 같습니다. 그런데 앞에 정시원 멘토님이 조언해주신 말씀을 보고 찾아보니 private 함수 앞에 붙여주는 일종의 자바스크립트 컨벤션이더라구요!

(todo: string): void => {
dispatch({
type: "ADD_DONE",
todo: { text: todo },
});
},
[dispatch],
);

// todo item 삭제
const _deleteTodoList = useCallback(
(idx: number): void => {
dispatch({
type: "DELETE_TODO",
idx,
});
},
[dispatch],
);

return (
<TodoContents>
<h3>TO DO ({todoList.length})</h3>
<ul>
{todoList.map(({ text }, idx) => (
<TodoItem
key={idx}
type="todo"
todo={text}
idx={idx}
deleteCurrentList={_deleteTodoList}
addToggleList={_addDoneList}
/>
))}
</ul>
</TodoContents>
);
};

const TodoContents = styled.section`
padding: 0 20px;
border-bottom: 1px solid lightgrey;
`;

export default TodoList;
5 changes: 5 additions & 0 deletions src/components/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import TodoInputForm from "./TodoInputForm";
import TodoList from "./TodoList";
import DoneList from "./DoneList";

export { TodoInputForm, TodoList, DoneList };
Loading