💡 TodoList 기능
📁 VS Code
🔎 TodoList.js
import React, { useState, useContext } from 'react';
import { TodoListContext } from './App';
const TodoList = () => {
const {setTodoList, loginMember, todoList} = useContext(TodoListContext);
const [inputTodo, setInputTodo] = useState('');
let keyIndex = 0;
const handleAddTodo = () => {
if(inputTodo.trim().length === 0){
alert('할 일을 입력해 주세요.');
return;
}
fetch("/todo", {
method : "POST",
headers : {"Content-Type" : "application/json"},
body : JSON.stringify({
title : inputTodo,
todoMemberNo : loginMember.todoMemberNo
})
})
.then(resp => resp.text())
.then(todoNo => {
if(Number(todoNo) === 0){
return;
}
const newTodo = {
todoNo : todoNo,
title : inputTodo,
todoMemberNo : loginMember.todoMemberNo,
isDone : "X"
};
const newTodoList = [...todoList, newTodo];
setTodoList(newTodoList);
setInputTodo('');
})
.catch(e => console.log(e))
}
const handleToggleTodo = (todo, index) => {
fetch("/todo", {
method : "PUT",
headers : {"Content-Type" : "application/json"},
body : JSON.stringify({
"todoNo" : todo.todoNo,
"isDone" : todo.isDone === 'O'? 'X' : 'O'
})
})
.then(resp => resp.text())
.then(result => {
if(result === '0'){
console.log('업데이트 실패!');
return;
}
const newTodoList = [...todoList];
newTodoList[index].isDone = newTodoList[index].isDone === 'O'? 'X' : 'O';
setTodoList(newTodoList);
})
.catch(e=>console.log(e));
}
const handleDeleteTodo = (todoNo, index) => {
fetch("/todo", {
method : "DELETE",
headers : {"Content-Type" : "application/json"},
body : todoNo
})
.then(resp => resp.text())
.then(result => {
if(result === '0'){
alert("삭제 실패!");
return;
}
const newTodoList = [...todoList];
newTodoList.splice(index, 1);
setTodoList(newTodoList);
})
.catch(e=>console.log(e))
}
return(
<>
<h1>{loginMember.name}의 Todo List</h1>
<div className="todo-container">
<h3>할 일(Todo) 입력</h3>
<div>
<input type="text" value={inputTodo} onChange={e => setInputTodo(e.target.value)} />
<button onClick={handleAddTodo}>Todo 추가</button>
</div>
<ul>
{}
{todoList.map((todo, index) => (
<li key={keyIndex++}>
<div>
<span className={todo.isDone === 'O' ? 'todo-compleate' : ''}> {todo.title} </span>
<span>
<button onClick={() => { handleToggleTodo(todo, index) }}>{todo.isDone}</button>
<button onClick={() => { handleDeleteTodo(todo.todoNo, index) }}>삭제</button>
</span>
</div>
</li>
))}
</ul>
</div>
</>
);
};
export default TodoList;
🔎 App.js
import React, { useState, createContext } from 'react';
import './App.css';
import SignupContainer from './Signup';
import Login from './Login';
import TodoList from './TodoList';
export const TodoListContext = createContext();
function App() {
const [signupView, setSignupView] = useState(false);
const [loginMember, setLoginMember] = useState(null);
const [todoList, setTodoList] = useState([]);
return (
<TodoListContext.Provider value={ {setTodoList, setLoginMember, loginMember, todoList} }>
<button onClick={ () => {setSignupView(!signupView)} }>
{ signupView ? ('회원 가입 닫기') : ('회원 가입 열기') }
</button>
<div className='signup-wrapper'>
{}
{}
{signupView === true && (<SignupContainer/>)}
</div>
<h1>Todo List</h1>
<Login />
<hr/>
{}
{ loginMember && (<TodoList/>) }
</TodoListContext.Provider>
);
}
export default App;
🔎 App.css
...
.todo-container{
padding: 20px;
width: 500px;
}
.todo-container li{
margin-bottom: 10px;
}
.todo-container li > div{
display: flex;
justify-content: space-between;
}
.todo-container li > div > span:last-child{
display: flex;
}
.todo-container li > div button{
margin: 0 5px;
}
.todo-compleate{
text-decoration: line-through;
}
📁 Spring
🔎 TodoController.java
...
@PostMapping("/todo")
public int insert(@RequestBody Todo todo) {
return service.insert(todo);
}
@PutMapping("/todo")
public int update(@RequestBody Todo todo) {
return service.update(todo);
}
@DeleteMapping("/todo")
public int delete(@RequestBody int todoNo) {
return service.delete(todoNo);
}
🔎 TodoService.java
...
int insert(Todo todo);
int update(Todo todo);
int delete(int todoNo);
🔎 TodoServiceImpl.java
...
@Transactional(rollbackFor = Exception.class)
@Override
public int insert(Todo todo) {
int result = dao.insert(todo);
return result > 0 ? todo.getTodoNo() : 0;
}
@Transactional(rollbackFor = Exception.class)
@Override
public int update(Todo todo) {
return dao.update(todo);
}
@Transactional(rollbackFor = Exception.class)
@Override
public int delete(int todoNo) {
return dao.delete(todoNo);
}
🔎 TodoDao.java
...
public List<Todo> selectTodoLst(int todoMemberNo){
return sqlSession.selectList("todoMapper.selectTodoLst", todoMemberNo);
}
public int insert(Todo todo) {
return sqlSession.insert("todoMapper.insert", todo);
}
public int update(Todo todo) {
return sqlSession.update("todoMapper.update", todo);
}
public int delete(int todoNo) {
return sqlSession.delete("todoMapper.delete", todoNo);
🔎 todo-mapper.xml
...
<select id="selectTodoLst" resultMap="todo_rm">
SELECT * FROM TODO_LIST
WHERE TODO_MEMBER_NO = #{todoMemberNo}
ORDER BY 1
</select>
<insert id="insert" useGeneratedKeys="true">
<selectKey order="BEFORE" keyProperty="todoNo" resultType="_int" >
SELECT SEQ_TODO_NO.NEXTVAL FROM DUAL
</selectKey>
INSERT INTO TODO_LIST
VALUES(${todoNo}, #{title}, default, ${todoMemberNo})
</insert>
<update id="update">
UPDATE TODO_LIST SET
IS_DONE = #{isDone}
WHERE TODO_NO = ${todoNo}
</update>
<delete id="delete">
DELETE FROM TODO_LIST
WHERE TODO_NO = ${todoNo}
</delete>
...
💻 구현 화면