에러가 난 원인이 components에 있는 TodoContext함수를 인식을 못해서 였는데
폴더 이름과 함수 이름을 바꿔 보아도 해결되지 않아서
TodoContext함수만 따로 빼주었습니다.
+ 버튼을 누르면 45도 회전시켜서 X버튼으로 보이게 하고
할일을 입력할 수 있는 인풋 창이 생성됩니다.
여기서 처음 알게 된 것은
라는 css 속성인데 border-box로 설정하면 요소의 width 값은
'콘텐츠 크기 + 좌우 padding 값 + 좌우 border 값'으로 계산되는 것입니다.
즉 width값이 100%이기 때문에 요소의 크기와 width 값이 동일하게 적용됩니다.
이제 UI 부분은 모두 구현된 것 같고
기능을 구현해 보도록 하겠습니다.
import React from 'react';
import styled from 'styled-components';
import { useTodoState } from '../TodoContext';
const TodoHeadBlock = styled.div`
padding-top: 48px;
padding-left: 32px;
padding-right: 32px;
padding-bottom: 24px;
border-bottom: 1px solid #e9ecef;
h1 {
margin: 0;
font-size: 36px;
color: #343a40;
}
.day {
margin-top: 4px;
color: #868e96;
font-size: 21px;
}
.tasks-left {
color: #20c997;
font-size: 18px;
margin-top: 40px;
font-weight: bold;
}
`;
function TodoHead() {
const todos = useTodoState();
const undoneTasks = todos.filter(todo => !todo.done);
return (
<TodoHeadBlock>
<h1>2019년 7월 10일</h1>
<div className="day">수요일</div>
<div className="tasks-left">할 일 {undoneTasks.length}개 남음</div>
</TodoHeadBlock>
);
}
export default TodoHead;
먼저 TodoHead.js에서 할 일의 개수가 몇 개 남았는지 구현합니다.
여기서 filter는 괄호 안에 해당되는 요소들로 새로운 배열을 만들어 주는데
괄호 안에 내용은 todo.done상태가 아닌 것을 의미하고
완료되지 않은 할 일들로 이루어진 배열을 만들어 줄 것입니다.
이 배열의 길이를 출력하면 완료되지 않은 할 일의 개수를 알려줄 것입니다.
할 일의 상태는 TodoContext에서 관리합니다.
done 상태가 false인 할 일이 2개가 있기 때문에
할 일이 2개 남았다고 표시해 주는 것입니다.
다음은 날짜를 오늘의 날짜로 변경해 주는 기능을 구현합니다.
import React from 'react';
import styled from 'styled-components';
import { useTodoState } from '../TodoContext';
const TodoHeadBlock = styled.div`
padding-top: 48px;
padding-left: 32px;
padding-right: 32px;
padding-bottom: 24px;
border-bottom: 1px solid #e9ecef;
h1 {
margin: 0;
font-size: 36px;
color: #343a40;
}
.day {
margin-top: 4px;
color: #868e96;
font-size: 21px;
}
.tasks-left {
color: #20c997;
font-size: 18px;
margin-top: 40px;
font-weight: bold;
}
`;
function TodoHead() {
const todos = useTodoState();
const undoneTasks = todos.filter(todo => !todo.done);
const today = new Date();
const dateString = today.toLocaleDateString('ko-KR', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
const dayName = today.toLocaleDateString('ko-KR', { weekday: 'long' });
return (
<TodoHeadBlock>
<h1>{dateString}</h1>
<div className="day">{dayName}</div>
<div className="tasks-left">할 일 {undoneTasks.length}개 남음</div>
</TodoHeadBlock>
);
}
export default TodoHead;
먼저 new Date()로 오늘의 날짜를 불러오고
toLocaleDateString이라는 함수를 써서 날짜를 상세히 표시할 수 있습니다.
'ko-KR'은 한국어로 표시해달라는 의미이고
year, month, day, minute등의 단위를 타입을 주어 표시할 수 있습니다.
보통은 month를 영어로 표시할 때만 'long'타입을 쓰고
나머지는 숫자로 표시하기 위해 'numeric'을 씁니다.
날짜가 최신화 된 모습!
다음은 TodoList에서 state를 조회하고 렌더링 해줍니다.
map함수를 이용해서 TodoItem의 요소들을 렌더링 해줍니다.
onToggle, onRemove와 같은 세부 기능은 TodoItem에서 관리합니다.
import React from 'react';
import styled, { css } from 'styled-components';
import { MdDone, MdDelete } from 'react-icons/md';
import { useTodoDispatch } from '../TodoContext';
const Remove = styled.div`
display: flex;
align-items: center;
justify-content: center;
color: #dee2e6;
font-size: 24px;
cursor: pointer;
opacity: 0;
&:hover {
color: #ff6b6b;
}
`;
const TodoItemBlock = styled.div`
display: flex;
align-items: center;
padding-top: 12px;
padding-bottom: 12px;
&:hover {
${Remove} {
opacity: 1;
}
}
`;
const CheckCircle = styled.div`
width: 32px;
height: 32px;
border-radius: 16px;
border: 1px solid #ced4da;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20px;
cursor: pointer;
${props =>
props.done &&
css`
border: 1px solid #38d9a9;
color: #38d9a9;
`}
`;
const Text = styled.div`
flex: 1;
font-size: 21px;
color: #495057;
${props =>
props.done &&
css`
color: #ced4da;
`}
`;
function TodoItem({ id, done, text }) {
const dispatch = useTodoDispatch();
const onToggle = () => dispatch({ type: 'TOGGLE', id });
const onRemove = () => dispatch({ type: 'REMOVE', id });
return (
<TodoItemBlock>
<CheckCircle done={done} onClick={onToggle}>
{done && <MdDone />}
</CheckCircle>
<Text done={done}>{text}</Text>
<Remove onClick={onRemove}>
<MdDelete />
</Remove>
</TodoItemBlock>
);
}
export default TodoItem;
TodoItem에서는 상태가 'done'인지 아닌지에 따라서 시각적으로 보이는 부분을
css에 변화를 주어 변경하고
onToggle, onRemover를 dispatch를 통해서 관리합니다.
Dispatch는 TodoContext에서 리듀서를 통해 이미 만들어 놨습니다.
마지막으로는 TodoCreate에서 작업합니다.
TodoCreate에서는 인풋창에 대한 css를 변경하고
onSubmit에서는 open이라는 초기의 상태를 만들어서
생성했을 때의 done 상태를 'false'로 두고 value를 초기화합니다.
마지막 줄에는 React.memo로 감싸주면 불필요한 렌더링을 방지할 수 있다고 합니다.
할 일을 추가하면 변경점들이 적용되는지 볼까요?
이렇게 할 일이 추가되고 할 일의 개수도 늘어나는 것을 볼 수 있습니다.
그리고 우측의 쓰레기통 아이콘을 누르면 삭제되는 것이 신기하네요.
코드를 따라하는 것에 불과하지만 변경점들이 시각적으로 보이는 것이
즐거웠고 여러가지 리액트의 라이브러리를 사용해보면서
공부할 수 있는 시간을 가질 수 있어서 좋았던 것 같습니다.
다음 시간에는 db를 공부해서 로그인 창을 구현해 보도록 하겠습니다.
다른 추가할 사항이 있으면 그 쪽을 공부할 수도 있을 것 같습니다.
읽어주셔서 감사합니다!
'React' 카테고리의 다른 글
[React] 투두리스트 로그인 구현하기2 (0) | 2024.01.22 |
---|---|
[React] 투두리스트 로그인 구현하기1 (0) | 2024.01.21 |
[React] 투두리스트 웹 만들기 2 (0) | 2024.01.17 |
[React] 투두리스트 웹 만들기 (1) | 2024.01.16 |
[React] 리액트로 서버에 데이터 연동하기2 (1) | 2023.11.22 |