Category: To do List

0

리엑트 Todo List 만들기 3 - Context API를 이용해 상태 관리하기

리엑트 Todo List 만들기 1 - 기본 템플릿 만들기 리엑트 Todo List 만들기 2 - 리스트 항목 만들기 리엑트 Todo List 만들기 3 - Context API를 이용해 상태 관리하기 리엑트 Todo List 만들기 3 - Context API를 이용해 상태 관리하기Context API 사용 설정하기Reducer 생성function todoReducer(state, action) { switch (action.type) { case "CREATE": return state.concat(action.todo); case "TOGGLE": return state.map((todo) => todo.id === action.id ? { ...todo, done: !todo.done } : todo ); case "REMOVE": return state.filter((todo) => todo.id !== action.id); default: throw new Error(`Unhandled action type: ${action.type}`); }} Conext API 적용하기const TodoStateContext = createContext();const TodoDispatchContext = createContext();const TodoNextIdContext = createContext();export function TodoProvider({ children }) { const [state, dispatch] = useReducer(todoReducer, initialTodos); const nextId = useRef(5); return ( <TodoStateContext.Provider value={state}> <TodoDispatchContext.Provider value={dispatch}> <TodoNextIdContext.Provider value={nextId}> {children} </TodoNextIdContext.Provider> </TodoDispatchContext.Provider> </TodoStateContext.Provider> );} Context 사용을 위한 Custom Hook 생성export function useTodoState() { return useContext(TodoStateContext);}export function useTodoDispatch() { return useContext(TodoDispatchContext);}export function useTodoNextId() { return useContext(TodoNextIdContext);}

0

리엑트 Todo List 만들기 2 - 리스트 항목 만들기

리엑트 Todo List 만들기 1 - 기본 템플릿 만들기 리엑트 Todo List 만들기 2 - 리스트 항목 만들기 리엑트 Todo List 만들기 3 - Context API를 이용해 상태 관리하기 리엑트 Todo List 만들기 2- 리스트 항목 만들기 TodoCreate.js import React, { useState } from 'react';import styled, { css } from 'styled-components';import { MdAdd } from 'react-icons/md';const CircleButton = styled.button` background: #38d9a9; &:hover { background: #63e6be; } &:active { background: #20c997; } z-index: 5; cursor: pointer; width: 80px; height: 80px; display: block; align-items: center; justify-content: center; font-size: 60px; position: absolute; left: 50%; bottom: 0px; transform: translate(-50%, 50%); color: white; border-radius: 50%; border: none; outline: none; display: flex; align-items: center; justify-content: center; transition: 0.125s all ease-in; ${props => props.open && css` background: #ff6b6b; &:hover { background: #ff8787; } &:active { background: #fa5252; } transform: translate(-50%, 50%) rotate(45deg); `}`;const InsertFormPositioner = styled.div` width: 100%; bottom: 0; left: 0; position: absolute;`;const InsertForm = styled.form` background: #f8f9fa; padding-left: 32px; padding-top: 32px; padding-right: 32px; padding-bottom: 72px; border-bottom-left-radius: 16px; border-bottom-right-radius: 16px; border-top: 1px solid #e9ecef;`;const Input = styled.input` padding: 12px; border-radius: 4px; border: 1px solid #dee2e6; width: 100%; outline: none; font-size: 18px; box-sizing: border-box;`;function TodoCreate() { const [open, setOpen] = useState(false); const onToggle = () => setOpen(!open); const isOpen = (open) =>{ if(open){ return( <InsertFormPositioner> <InsertForm> <Input autoFocus placeholder="할 일을 입력 후, Enter 를 누르세요" /> </InsertForm> </InsertFormPositioner>) }else{ return null; } } return ( <div> {isOpen(open)} <CircleButton onClick={onToggle} open={open}> <MdAdd /> </CircleButton> </div> );}export default TodoCreate; TodoItem.js 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;

0

리엑트 Todo List 만들기 1 - 기본 템플릿 만들기

리엑트 Todo List 만들기 1 - 기본 템플릿 만들기 리엑트 Todo List 만들기 2 - 리스트 항목 만들기 리엑트 Todo List 만들기 3 - Context API를 이용해 상태 관리하기 리엑트 Todo List 만들기 1 - 기본 템플릿 만들기 TodoTemplate.js import React from "react";import styled from "styled-components";const TodoTemplateBlock = styled.div` width: 512px; height: 768px; position: relative; /* 추후 박스 하단에 추가 버튼을 위치시키기 위한 설정 */ background: white; border-radius: 16px; box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.04); margin: 0 auto; /* 페이지 중앙에 나타나도록 설정 */ margin-top: 96px; margin-bottom: 32px; display: flex; flex-direction: column;`;const TodoTemplate = ({ children }) => { return <TodoTemplateBlock>{children}</TodoTemplateBlock>;}export default TodoTemplate; TodoHead.js 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;