Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
421 changes: 388 additions & 33 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"styled-components": "^6.0.8",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
Binary file modified public/favicon.ico
Binary file not shown.
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
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>
<title>Song Seok TODO</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
96 changes: 91 additions & 5 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,95 @@
import React, { useState, useEffect } from "react";
import TodoList from "./components/todoList";
import DoneList from "./components/doneList";
import InputTodo from "./components/inputTodo";
import { createGlobalStyle } from 'styled-components'

const GlobalStyle = createGlobalStyle`
html{ font-size: 62.5%; }
Comment on lines +7 to +8

Choose a reason for hiding this comment

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

createGlobalStyle을 사용하여 전역 스타일을 정의할 수 있군요!!
또 html{ font-size: 62.5%; } 로 설정하면 1rem이 10px로 설정되는거 배우고 갑니다~!

main {
display: flex;
flex-direction: column;
width: 40rem;
height: 62rem;
margin: 3rem auto;
padding: 2.5rem;
background-color: #ffffff;
box-shadow: 0 0.2rem 0.4rem rgba(0, 0, 0, 0.1);
border-radius: 1.5rem;
}
h1 {
font-size: 3.5rem;
color: #000000;
text-align: center;
margin-bottom: 2rem;
}
`;

function App() {
return (
<div>
<h1>18기 프론트 화이팅~ 푸하항ㅋ</h1>
</div>
);
const [todos, setTodos] = useState([]);
const [dones, setDones] = useState([]);

useEffect(() => {
const savedTodos = localStorage.getItem("todos");
const savedDones = localStorage.getItem("dones");
if (savedTodos) setTodos(JSON.parse(savedTodos));
if (savedDones) setDones(JSON.parse(savedDones));
}, []);
Comment on lines +34 to +39

Choose a reason for hiding this comment

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

저는 todo, done 따로따로 localstorage에서 읽었는데, 이렇게 한방에 읽는 방법도 좋은 것 같아요~!


useEffect(() => {
localStorage.setItem("todos", JSON.stringify(todos));
localStorage.setItem("dones", JSON.stringify(dones));
}, [todos, dones]);
Comment on lines +41 to +44

Choose a reason for hiding this comment

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

요 부분도 useEffect 하나에 한번에 저장할 수 있었네요!

Copy link

Choose a reason for hiding this comment

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

저는 바뀔 때마다 일일이 따로 localStorage를 불러왔었는데, 확실히 이렇게 보니 useEffect로 쓰면 훨씬 간단하고 편리했었겠어요. 이렇게도 활용할 수 있는 점 배워갑니다!


const addTodo = (item) => {
setTodos([...todos, { id: new Date().getTime(), text: item }]);
};

const deleteItem = (listName, index) => {
const list = listName === "todos" ? todos : dones;
const newList = [...list];
newList.splice(index, 1);
listName === "todos" ? setTodos(newList) : setDones(newList);
Comment on lines +51 to +54

Choose a reason for hiding this comment

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

listName을 통해 삭제나 이동 여부를 판단하는 코드 직관적으로 이해하기 좋은 것 같습니다!

Copy link

Choose a reason for hiding this comment

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

동의합니다!! listName으로 조건을 주어 삭제, 이동여부를 판단해주셔서 코드 이해가 너무 좋았어요!

};

const switchList = (fromListName, index) => {
let fromList, toList, setFromList, setToList;

if (fromListName === "todos") {
fromList = todos;
toList = dones;
setFromList = setTodos;
setToList = setDones;
} else {
fromList = dones;
toList = todos;
setFromList = setDones;
setToList = setTodos;
}

const itemToMove = fromList[index];
const newFromList = [...fromList];
newFromList.splice(index, 1);
setFromList(newFromList);

const newToList = [...toList, itemToMove];
setToList(newToList);
};

Copy link

Choose a reason for hiding this comment

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

boolean 값으로 완료 여부 관리하는 state 하나 설정해주고 그 설정에 따라 특정 값만 출력하는 식으로 하면 코드가 간결해질 것 같아요!

return (
<>
<GlobalStyle />
<main>
<h1>할 일</h1>
<InputTodo addTodo={addTodo} />
<TodoList todos={todos} switchList={switchList} deleteItem={deleteItem} />
<DoneList dones={dones} switchList={switchList} deleteItem={deleteItem} />
</main>
</>
);
}

export default App;

44 changes: 44 additions & 0 deletions src/components/doneList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react";
import ItemList from "./itemList";
import styled from 'styled-components';


const ListSection = styled.section`
display: flex;
flex-direction: column;
height: 17rem;
overflow-y: auto;
Copy link

Choose a reason for hiding this comment

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

overflow-y를 auto로 해두었을 때, scroll이 생기기 전과 후에 스크롤 넓이 때문에 버튼의 위치가 달라지는데,
scrollbar-width: none 혹은 width 지정을 통해 scroll이 있을 때와 없을 때 위치 변화가 없게 해주면 좋을 것 같아요!

margin-bottom: 2rem;
word-break: break-all;
Copy link

Choose a reason for hiding this comment

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

word-wrap 속성만 알고 있었는데 word-break 속성도 있었군요! 줄바꿈의 기준을 설정해주는 속성을 배워갑니다..

`;

const Container = styled.div`
display: flex;
flex-direction: column;
width: 100%;
h2 {
font-size: 2rem;
}
`;

function DoneList({ dones, switchList, deleteItem }) {
return (
<Container>
<h2>Done</h2>
<ListSection>
{dones.map((done, index) => (
<ItemList
key={index}
item={done.text}
index={index}
switchList={() => switchList("dones", index)}
deleteItem={() => deleteItem("dones", index)}
/>
))}
</ListSection>
</Container>
);
}

export default DoneList;
68 changes: 68 additions & 0 deletions src/components/inputTodo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { useState } from 'react';
import styled from 'styled-components';

const AddButton = styled.button`
width: 9rem;
padding: 1.3rem;
margin-left: 2.5rem;
Comment on lines +5 to +7

Choose a reason for hiding this comment

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

rem 단위도 자유롭게 쓰시는 것 같아요!!👍

border: none;
background-color: #000000;
color: #fff;
border-radius: 0.5rem;
line-height: 1.8rem;
&:hover {
background-color: #FF2D00;
}
`;

const TodoInput = styled.input`
width: 24rem;
padding: 1rem;
border: 0.2rem solid #ddd;
border-radius: 0.5rem;
font-size: 1.8rem;
line-height: 1.8rem;
&:focus {
border-color: #007bff;
}
`;

const TodoContainer = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
`;

function InputTodo({ addTodo }) {
const [input, setInput] = useState('');

const addTodoTrim = () => {
if (input.trim().length > 0) {
addTodo(input.trim());
setInput('');
}
};

const enterKey = (e) => {
if (e.key === 'Enter') {
addTodoTrim();
}
};
Comment on lines +49 to +53

Choose a reason for hiding this comment

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

form태그로 감싸면 엔터 키를 눌렀을때 폼 제출이 발생해서 따로 엔터 키 처리를 하지 않아도 될 것 같아요! 참고해보시면 될것 같습니다~

Copy link

Choose a reason for hiding this comment

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

조건문 처리를 해준 김에 빈칸으로 제출될 시 alert 창이나 스낵바를 이용해 할 일을 입력해달라는 안내문구가 출력되면 사용자의 서비스 이해도가 올라갈 것 같습니다. trim을 적용하는 함수를 따로 만든 뒤 제출했을 때 적용하는 것도 좋지만, 제출 조건이 충족되는 것을 확인한 trim 조건문 안에 list에 등록되는 함수가 실행되도록 하는 방법도 좋을 것 같아요!


return (
<TodoContainer>
<TodoInput
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={enterKey}
/>
<AddButton onClick={addTodoTrim}>Add</AddButton>
</TodoContainer>
);
}

export default InputTodo;
57 changes: 57 additions & 0 deletions src/components/itemList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from "react";
import styled from 'styled-components';

const DeleteButton = styled.button`
background-color: #FFB6C1;
color: white;
border: none;
box-sizing: border-box;
padding: 0.6rem 0.5rem;
width: 6rem;
font-size: 1.4rem;
border-radius: 2rem;
box-shadow: 0 0.4rem 1rem rgba(255, 182, 193, 0.2);
margin-right: 0.5rem;
&:hover {
background-color: #FF69B4;
box-shadow: 0 0.4rem 1rem rgba(255, 105, 180, 0.4);
}
Comment on lines +16 to +19

Choose a reason for hiding this comment

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

hover에다가 cursor 속성을 추가해서 포인터로 바뀌는 효과 주면 시각적으로 더 좋을것 같아요~!

&:active {
box-shadow: 0 0.4rem 1rem rgba(255, 105, 180, 0.2);
}
Copy link

Choose a reason for hiding this comment

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

hover일 때와 active일 때 투명도를 다르게 주는 디테일 좋아요~!!

`;

const TodoItemContainer = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.8rem;
margin: 0.8rem 0;
cursor: pointer;
`;

const TodoText = styled.span`
flex-grow: 1;
margin-right: 1rem;
font-size : 1.6rem;
`;

const ActionsContainer = styled.div`
display: flex;
align-items: center;
`;

function ItemList({ item, index, switchList, deleteItem }) {
return (
<TodoItemContainer onClick={switchList}>
<TodoText>{item}</TodoText>
<ActionsContainer>
<DeleteButton onClick={(e) => { e.stopPropagation(); deleteItem(); }}>x</DeleteButton>
Copy link

Choose a reason for hiding this comment

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

handleDeleteClick 과 같은 함수를 따로 만들어서 이벤트 발생 시 실행되는 함수를 넣고 onClick 시에는 handleDeleteClick 함수만 불러와도 좋을 것 같아요. 개인적인 선호일 수도 있지만 저는 이 방식이 코드가 더 읽기 쉽고 유지보수하기 편해지더라구요!

</ActionsContainer>
</TodoItemContainer>
);
}

export default ItemList;
44 changes: 44 additions & 0 deletions src/components/todoList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react";
import ItemList from "./itemList";
import styled from 'styled-components';


const ListSection = styled.section`
display: flex;
flex-direction: column;
height: 17rem;
overflow-y: auto;
margin-bottom: 2rem;
word-break: break-all;

Choose a reason for hiding this comment

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

요소가 길어지면 자동으로 줄바꾸는데 사용되는 속성이 있었군요! 배우고 갑니다~!

`;

const Container = styled.div`
display: flex;
flex-direction: column;
width: 100%;
h2 {
font-size: 2rem;
}
`;

function TodoList({ todos, switchList, deleteItem }) {
return (
<Container>
<h2>Todo</h2>
<ListSection>
{todos.map((todo, index) => (
<ItemList
key={index}
item={todo.text}
index={index}
switchList={() => switchList("todos", index)}
deleteItem={() => deleteItem("todos", index)}
/>
))}
</ListSection>
</Container>
);
}

export default TodoList;