반응형
컴포넌트: Todo, Button
추가기능: 가로스크롤
id를 Date.now()로 지정해 id 겹침현상 제거
완료된 모습
App.js
import React, { useState } from 'react';
import './App.css';
import Todo from './components/Todo';
import CustomBtn from './components/CustomBtn';
function App() {
const [todo, setTodo] = useState([
{
id: Date.now(),
title: 'todotest',
contents: '리액트기초를 공부해봅시다.',
},
{
id: Date.now() + 1,
title: 'todotest222',
contents: '리액트기초를 공부해봅시다.',
},
]);
const [doneTodo, setDoneTodo] = useState([]);
const [title, setTitle] = useState('');
const [contents, setContents] = useState('');
const addTodoHandler = () => {
const newTodo = {
id: Date.now(),
title: title,
contents: contents,
};
if (title === '' && contents === '') alert('내용을 추가하세요');
else setTodo([...todo, newTodo]);
};
// 할일삭제기능
const deleteTodoHandler = (id) => {
setTodo(todo.filter((t) => t.id !== id));
};
// 완료삭제기능
const deleteDoneTodoHandler = (id) => {
setDoneTodo(doneTodo.filter((dt) => dt.id !== id));
};
// 할일완료기능
const doneTodoHandler = (dt) => {
const newDoneTodo = {
id: dt.id,
title: dt.title,
contents: dt.contents,
};
setDoneTodo([...doneTodo, newDoneTodo]);
setTodo(todo.filter((t) => t.id !== dt.id));
};
// 완료취소기능
const doneCancelHandler = (t) => {
const newTodo = {
id: t.id,
title: t.title,
contents: t.contents,
};
setTodo([...todo, newTodo]);
setDoneTodo(doneTodo.filter((dt) => t.id !== dt.id));
};
return (
<div className='Outer'>
<div className='InputArea'>
제목
<input
className='Input'
value={title}
onChange={(e) => setTitle(e.target.value)}
></input>
내용
<input
className='Input'
value={contents}
onChange={(e) => setContents(e.target.value)}
></input>
<CustomBtn buttonColor='#6B615F' onClick={addTodoHandler}>
추가하기
</CustomBtn>
</div>
<div className='Outer'>
<h2 className='title'>✅Todo</h2>
<div className='Scroll'>
{todo.map((todo) => {
return (
<Todo
todo={todo}
title={todo.title}
key={todo.id}
contents={todo.contents}
firstHandler={deleteTodoHandler}
secondHandler={doneTodoHandler}
firstButton='삭제하기'
secondButton='완료하기'
color='#FFB8B0'
/>
);
})}
</div>
<h2 className='title'>🐾Done</h2>
<div className='Scroll'>
{doneTodo.map((doneTodo) => {
return (
<Todo
todo={doneTodo}
title={doneTodo.title}
key={doneTodo.id}
contents={doneTodo.contents}
firstHandler={deleteDoneTodoHandler}
secondHandler={doneCancelHandler}
firstButton='삭제하기'
secondButton='취소하기'
color='#5DA37F'
/>
);
})}
</div>
</div>
</div>
);
}
export default App;
./components/Todo.js
import React from 'react';
import '../App.js';
import CustomBtn from './CustomBtn.js';
function Todo(props) {
const { title, contents, todo, firstButton, secondButton, color } = props;
//두번째 버튼이 취소하기면 버튼 색상 변경하기
if (secondButton === '취소하기')
return (
<div style={{ borderColor: color }} className='Box'>
<p>{title}</p>
<p>{contents}</p>
<p>
<CustomBtn
buttonColor='#c1e8d4'
onClick={() => props.firstHandler(todo.id)}
>
{firstButton}
</CustomBtn>
<CustomBtn
buttonColor='#c1e8d4'
onClick={() => props.secondHandler(todo)}
>
{secondButton}
</CustomBtn>
</p>
</div>
);
return (
<div style={{ borderColor: color }} className='Box'>
<p>{title}</p>
<p>{contents}</p>
<p>
<CustomBtn
buttonColor='#eb948a'
onClick={() => props.firstHandler(todo.id)}
>
{firstButton}
</CustomBtn>
<CustomBtn
buttonColor='#eb948a'
onClick={() => props.secondHandler(todo)}
>
{secondButton}
</CustomBtn>
</p>
</div>
);
}
export default Todo;
./components/CustomBtn.js
import React from 'react';
import '../App.js';
const CustomBtn = (props) => {
const { onClick, children, buttonColor } = props;
return (
<button
style={{ backgroundColor: buttonColor }}
onClick={onClick}
className='Button'
>
{children}
</button>
);
};
export default CustomBtn;
App.css
@font-face {
font-family: 'twayair';
src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_tway@1.0/twayair.woff')
format('woff');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Pretendard-Regular';
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff')
format('woff');
font-weight: 400;
font-style: normal;
}
* {
/* justify-content: center; */
align-items: center;
font-family: 'Pretendard-Regular';
}
.Outer {
padding-top: 30px;
width: 800px;
margin: 0 auto 0 auto;
}
.Scroll {
overflow: auto;
white-space: nowrap;
margin: 0 auto;
display: flex;
}
.InputArea {
display: flex;
padding: 10px auto 0 auto;
gap: 10px;
/* width: 800px; */
height: 50px;
background-color: #cbd2d3;
border-radius: 10px;
align-items: center;
justify-content: center;
}
.Input {
border: 0px;
height: 25px;
}
.title {
font-family: 'twayair';
}
.Box {
width: 300px;
border: 3px solid;
border-radius: 10px;
height: 150px;
align-self: center;
justify-content: center;
align-items: center;
margin: 10px;
display: flex;
flex-direction: column;
}
.Button {
/* color: white; */
border: 0px;
border-radius: 50px;
height: 30px;
margin: 0 10px;
}
vercel을 이용한 배포
반응형
'매일 해내는 개발 > React' 카테고리의 다른 글
[React] Todo리스트 Redux로 만들기 (0) | 2022.12.14 |
---|---|
[Redux] 리덕스란? (0) | 2022.12.13 |
[React] 투두리스트 만들기 (1) | 2022.12.13 |
[React] 리액트의 생명주기 (0) | 2022.12.08 |
[React] 리액트 기초 개념 컴포넌트/JSX/Props/State (0) | 2022.12.05 |
댓글