요즘 너무 바쁘지만 앱 개발을 꼭 하겠다는 의지로 살고 있다.
그런데 나는 이런 간단한 것조차 내 머리로 바로바로 되지 않는 것에 한탄하며 결국 기초부터 다지자는 생각으로 이번 글을 작성한다.
같이 시작해보자
1. UI 구성하기
- new Date().toDateString() : 시간 출력해주는 함수 !! => 기억하자 계속 까먹는다
- new Date().toLocaleDateString()
import './App.css'
function App() {
return (
<div className='app'>
<section className='header'>
<h3>오늘은🐰</h3>
<h1>{new Date().toDateString()}</h1>
</section>
<section className='editor'>
<input placeholder='새로운 Todo...'></input>
<button>추가</button>
</section>
<h4>Todo List⏳</h4>
<section className='list'>
<input placeholder='검색어를 입력하세요'></input>
<ul>
<input type='checkbox'></input>
<li className='content'>리액트 공부하기</li>
<li className='date'>{new Date().toLocaleDateString()}</li>
<button>삭제</button>
</ul>
<ul>
<input type='checkbox'></input>
<li className='content'>리액트 공부하기</li>
<li className='date'>{new Date().toLocaleDateString()}</li>
<button>삭제</button>
</ul>
</section>
</div>
)
}
export default App
.app{
display: flex;
flex-direction: column;
width:50%;
margin: 40px auto;
gap: 20px;
}
ul, li{
text-decoration: none;
list-style: none;
}
h1, h3{
margin: 0;
/* border: 1px solid rebeccapurple; */
}
.header{
display: flex;
flex-direction: column;
gap: 20px;
}
.header > h1{
color: blueviolet
}
.editor{
display: flex;
gap: 10px;
}
.editor > input{
flex: 1;
padding: 10px;
border: 1px solid rgb(209, 209, 209);
border-radius: 6px;
}
.editor button{
border: none;
width: 80px;
height: 50px;
background-color: blueviolet;
color: white;
border-radius: 6px;
}
.list{
display: flex;
gap: 10px;
flex-direction: column;
}
.list > input{
padding: 16px 4px;
flex: 1;
border: none;
border-bottom: 1px solid rgb(209, 209, 209);
outline: none;
}
.list > input:focus{
border-bottom: 1px solid blueviolet;
}
.list > ul{
padding: 20px 0;
display: flex;
flex-direction: row;
gap: 10px;
border-bottom: 1px solid rgb(212, 212, 212);
margin: 0;
/* border: 1px solid rebeccapurple; */
}
.list .content{
flex: 1;
}
.list .date{
font-size: small;
}
.list button{
border: none;
}
2. 분할하기
이제부터 좀 긴장된다.. 이게뭐라고
import './App.css'
import Header from './comopents/Header'
import List from './comopents/List'
import Editor from './comopents/Editor'
function App() {
return (
<div className='app'>
<Header></Header>
<Editor></Editor>
<h4>Todo List⏳</h4>
<List></List>
</div>
)
}
export default App
const Header = () => {
return(
<section className='header'>
<h3>오늘은🐰</h3>
<h1>{new Date().toDateString()}</h1>
</section>
);
}
export default Header;
const Editor = () => {
return(
<section className='editor'>
<input placeholder='새로운 Todo...'></input>
<button>추가</button>
</section>
);
}
export default Editor;
const List = () => {
return(
<section className='list'>
<input placeholder='검색어를 입력하세요'></input>
<ul>
<input type='checkbox'></input>
<li className='content'>리액트 공부하기</li>
<li className='date'>{new Date().toLocaleDateString()}</li>
<button>삭제</button>
</ul>
<ul>
<input type='checkbox'></input>
<li className='content'>리액트 공부하기</li>
<li className='date'>{new Date().toLocaleDateString()}</li>
<button>삭제</button>
</ul>
</section>
);
}
export default List;
엥 생각보다 금방끝냈다 (당황)
3. 입력받은 content를 list에 추가하기
새로운 todo 추가하기
할 수 있을까..? 당연하지 나 개발 토순이는 할 수 있다. 성공해버렸다
핵심은? map 함수를 사용하여 입력받은 값을 출력해주자!
App.jsx
import './App.css'
import { useState, useRef } from 'react'
import Header from './comopents/Header'
import List from './comopents/List'
import Editor from './comopents/Editor'
const mockup = [
{
id:0,
checkbox:false,
content:"리액트 공부하기",
date: new Date().getTime(),
},
{
id:1,
checkbox:false,
content:"리액트 공부하기1",
date: new Date().getTime(),
},
{
id:2,
checkbox:false,
content:"리액트 공부하기2",
date: new Date().getTime(),
},
]
function App() {
const [todo,setTodo] = useState(mockup);
const idRef = useRef(3);
const onCreate = (content) =>{
const newTodo = {
id:idRef.current++,
checkbox:false,
content:content,
date:new Date().getTime(),
}
setTodo([newTodo,...todo]);
}
return (
<div className='app'>
<Header></Header>
<Editor onCreate={onCreate}></Editor>
<h4>Todo List⏳</h4>
<List todo={todo}></List>
</div>
)
}
export default App
Editor.jsx
import { useState, useRef } from 'react'
const Editor = ({onCreate}) => {
const [content, setContent] = useState("");
const contentRef = useRef();
const onChangeContent = (e) => {
setContent(e.target.value);
}
const onSubmit = () => {
if(content===""){
contentRef.current.focus();
return;
}
onCreate(content);
setContent("");
}
return(
<section className='editor'>
<input ref={contentRef} value={content} onChange={onChangeContent} placeholder='새로운 Todo...'></input>
<button onClick={onSubmit}>추가</button>
</section>
);
}
export default Editor;
List.jsx
🐰 리스트를 전달할때는 key값(여기서는 id값)을 전달해야 한다.
import TodoItem from "./TodoItem";
const List = ({todo, onUpdate}) => {
return(
<section className='list'>
<input placeholder='검색어를 입력하세요'></input>
<div className="todos_wrapper">
{todo.map((todos)=>{
return <TodoItem key={todo.id} {...todos}></TodoItem>
})}
</div>
</section>
);
}
export default List;
TodoItem.jsx
import './TodoItem.css'
const TodoItem = ({id, isDone, content, date, onUpdate}) => {
return(
<div className="todoitem">
<input type='checkbox'></input>
<li className='content'>{content}</li>
<li className='date'>{new Date().toLocaleDateString()}</li>
<button>삭제</button>
</div>
);
}
export default TodoItem;
4. 검색기능 추가하기
App.jsx
import './App.css'
import { useState, useRef } from 'react'
import Header from './comopents/Header'
import List from './comopents/List'
import Editor from './comopents/Editor'
const mockup = [
{
id:0,
checkbox:false,
content:"리액트 공부하기",
date: new Date().getTime(),
},
{
id:1,
checkbox:false,
content:"리액트 공부하기1",
date: new Date().getTime(),
},
{
id:2,
checkbox:false,
content:"리액트 공부하기2",
date: new Date().getTime(),
},
]
function App() {
const [todo,setTodo] = useState(mockup);
const idRef = useRef(3);
const onCreate = (content) =>{
const newTodo = {
id:idRef.current++,
checkbox:false,
content:content,
date:new Date().getTime(),
}
setTodo([newTodo,...todo]);
}
const onUpdate = (targetId) => {
setTodo(todo.map((todos)=>{
if(todos.id === targetId){
return{
...todo,
isDone:!todo.isDone
}
}
return todos;
}))
}
return (
<div className='app'>
<Header></Header>
<Editor onCreate={onCreate}></Editor>
<h4>Todo List⏳</h4>
<List todo={todo} onUpdate={onUpdate}></List>
</div>
)
}
export default App
List.jsx
import TodoItem from "./TodoItem";
import { useState } from "react";
const List = ({todo, onUpdate}) => {
const [search, setSearch] = useState("");
const onChangeSearch = (e) => {
setSearch(e.target.value);
}
const getFilterdData = () => {
if(search===""){return todo;}
return todo.filter((todos)=>todos.content.toLowerCase().includes(search.toLowerCase()));
}
const filteredTodos = getFilterdData();
return(
<section className='list'>
<input value={search} onChange={onChangeSearch} placeholder='검색어를 입력하세요'></input>
<div className="todos_wrapper">
{filteredTodos.map((todos)=>{
return <TodoItem key={todo.id} {...todos} onUpdate={onUpdate}></TodoItem>
})}
</div>
</section>
);
}
export default List;
5. 체크되도록하기 & 삭제하기
App.jsx
import './App.css'
import { useState, useRef } from 'react'
import Header from './comopents/Header'
import List from './comopents/List'
import Editor from './comopents/Editor'
const mockup = [
{
id:0,
checkbox:false,
content:"리액트 공부하기",
date: new Date().getTime(),
},
{
id:1,
checkbox:false,
content:"리액트 공부하기1",
date: new Date().getTime(),
},
{
id:2,
checkbox:false,
content:"리액트 공부하기2",
date: new Date().getTime(),
},
]
function App() {
const [todo,setTodo] = useState(mockup);
const idRef = useRef(3);
const onCreate = (content) =>{
const newTodo = {
id:idRef.current++,
checkbox:false,
content:content,
date:new Date().getTime(),
}
setTodo([newTodo,...todo]);
}
const onUpdate = (targetId) => {
setTodo(todo.map((todos)=>{
if(todos.id === targetId){
return{
...todo,
isDone:!todo.isDone
}
}
return todos;
}))
}
const onDelete = (targetId) => {
// 인수 : todos 배열에서 targetId와 일치하는 id를 갖는 요소만 삭제한 새로운 배열
setTodo(todo.filter((todos)=>todos.id !== targetId))
}
return (
<div className='app'>
<Header></Header>
<Editor onCreate={onCreate}></Editor>
<h4>Todo List⏳</h4>
<List todo={todo} onUpdate={onUpdate} onDelete={onDelete}></List>
</div>
)
}
export default App
Editor.jsx
import { useState, useRef } from 'react'
const Editor = ({onCreate}) => {
const [content, setContent] = useState("");
const contentRef = useRef();
const onChangeContent = (e) => {
setContent(e.target.value);
}
const onSubmit = () => {
if(content===""){
contentRef.current.focus();
return;
}
onCreate(content);
setContent("");
}
return(
<section className='editor'>
<input ref={contentRef} value={content} onChange={onChangeContent} placeholder='새로운 Todo...'></input>
<button onClick={onSubmit}>추가</button>
</section>
);
}
export default Editor;
List.jsx
import TodoItem from "./TodoItem";
import { useState } from "react";
const List = ({todo, onUpdate, onDelete}) => {
const [search, setSearch] = useState("");
const onChangeSearch = (e) => {
setSearch(e.target.value);
}
const getFilterdData = () => {
if(search===""){return todo;}
return todo.filter((todos)=>todos.content.toLowerCase().includes(search.toLowerCase()));
}
const filteredTodos = getFilterdData();
return(
<section className='list'>
<input value={search} onChange={onChangeSearch} placeholder='검색어를 입력하세요'></input>
<div className="todos_wrapper">
{filteredTodos.map((todos)=>{
return <TodoItem key={todo.id} {...todos} onUpdate={onUpdate} onDelete={onDelete}></TodoItem>
})}
</div>
</section>
);
}
export default List;
TodoItem.jsx
import './TodoItem.css'
const TodoItem = ({id, isDone, content, date, onUpdate, onDelete}) => {
const onChangeCheckbox = () => {
onUpdate(id);
}
const onClickDeleteButton = () => {
onDelete(id);
}
return(
<div className="todoitem">
<input onChange={onChangeCheckbox} type='checkbox' checked={isDone}></input>
<li className='content'>{content}</li>
<li className='date'>{new Date(date).toLocaleDateString()}</li>
<button onClick={onClickDeleteButton}>삭제</button>
</div>
);
}
export default TodoItem;
마무리
이렇게 끝나버렸다. 시작도 안해봤는데 ㅎ
이제 손에 익히는 것만 남았다
이제는 실전이다
개발 이제 나한테 혼쭐날 일만 남았다
728x90
'DEVELOPE > 앱개발시작하기' 카테고리의 다른 글
[20240510] 앱개발 시작하기 #25 | 투두리스트 만들기 (0) | 2024.05.10 |
---|---|
[20240510] 앱개발 시작하기 #24 | 개발자 도구 사용하기 (0) | 2024.05.10 |
[20240510] 앱개발 시작하기 #23 | 라이프사이클 (LifeCycle) | useEffect (0) | 2024.05.10 |
[20240509] 앱개발 시작하기 #22 | Counter App (1) | 2024.05.09 |
[20240508] 앱개발 시작하기 #21 | 리액트 훅 (0) | 2024.05.08 |