React
[ React ] TodoList 4️⃣ 할일 o,x표시 / 추가 / 제거
Mungwang
2023. 9. 13. 09:14
💎 TodoList 3️⃣
- TodoList 3️⃣ 에 이어서 진행하는거라 참고하자!
[ React ] TodoList3️⃣ 로그인/로그아웃
💎 React code 📣 App.js - Login 처리를 위한 컴포넌트를 생성해주고 improt를 진행한다. - export const TodoListContext = createContext() : export 내보내기를 통해 TodoListContext를 전역변수로 사용하겠다!! : ContextApi
mungwang.tistory.com
💎 App.js
- {loginMember && (<TodoList/>)} : 로그인멤버가 담겨있으면 TodoList컴포넌트를 실행할거다.
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() {
// 회원가입, 로그인, 회원의 Todo List출력/추가/제거
const [ signupView, setSignupView ] = useState(false);
// 로그인한 회원 정보 저장
const [ loginMember, setLoginMember] = useState(null);
// 로그인한 회원의 todo-list를 저장
const [ todoList, setTodoList ] = useState([]);
return (
<TodoListContext.Provider value={ {setTodoList, setLoginMember, loginMember, todoList} }>
<button onClick={()=>{setSignupView(!signupView)}}>
{signupView ?('회원 가입 닫기') : ('회원가입 열기')}
</button>
<div className='signup-wrapper'>
{/* signupView가 true인 경우에만 회원 가입 컴포넌트 렌더링 */}
{/* 조건식 && true인 경우 */}
{signupView === true && (<SignupContainer/>)}
</div>
<h1>Todo List</h1>
<Login/>
<hr/>
// 9-13 추가
{loginMember && (<TodoList/>)}
</TodoListContext.Provider>
);
}
export default App;
💎 TodoList.js
- <li key={keyIndex++}> : let keyIndex =0; 라는 변수를 생성해서 key값으로 넣어준다
** React는 임의변수를 만들어 key값으로 사용하는걸 권장함! **
🔔 배열.splice(인덱스,몇칸) :: 배열의 인덱스 번째 요소부터 몇칸을 잘라내서 반환할지 지정
🔔 배열.map :: 기존 배열을 이용해서 새로운 배열 만들기
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 = () =>{
// 입력 X
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;
}
// 기존 todoList + 새로 추가된 Todo를 이용해
// 새 배열을 만들어
// todoList에 대입
// 새로 추가된 Todo 만들기
const newTodo = {
todoNo : todoNo,
title : inputTodo,
isDone : 'X',
todoMemberNo : loginMember.todoMemberNo
};
const newTodoList = [...todoList,newTodo];
setTodoList(newTodoList);
setInputTodo("");
})
.catch(e => console.log(e))
}
// O, X 업데이트
const handleToggleTodo = (todo,index) =>{
console.log(todo);
console.log(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(Number(result) === 0){ // 실패시 멈춤
console.log('업데이트 실패');
return;
}
// 수정 성공시 todoList 값을 변경해서 리렌더링
// todoList를 깊은 복사(똑같은 배열을 하나 더 만듬)
const newTodoList = [...todoList];
// index번째 요스의 O,X를 반대로 변경
newTodoList[index].isDone = newTodoList[index].isDone === 'O'? 'X' : 'O';
setTodoList(newTodoList);
})
.catch(e => console.log(e));
}
// 삭제
const handleDeleteTodo = (todoNo,index) =>{
console.log(todoNo)
fetch('/todo',{
method : 'delete',
headers : {'Content-Type' : 'application/json'},
body : todoNo
})
.then(resp => resp.text())
.then( result =>{
if(Number(result) === 0){ // 실패시 멈춤
console.log('업데이트 실패');
return;
}
const deleteTodoList = [...todoList];
deleteTodoList.splice(index,1);
setTodoList(deleteTodoList);
})
.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;
💎 Spring
📣 Dto
@Getter
@Setter
@ToString
public class Todo {
private int todoNo;
private String title;
private String isDone;
private int todoMemberNo;
}
📣 Controller
@RestController
public class TodoController {
// org.slf4j.Logger : 로그를 작성할 수 있는 객체
// org.slf4j.LoggerFactory
private Logger logger = LoggerFactory.getLogger(TodoController.class);
@Autowired
private TodoService service;
@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);
}
}
📣 Service
public interface TodoService {
int insert(Todo todo);
int update(Todo todo);
int delete(int todoNo);
}
📣 ServiceImpl
@Service
public class TodoServiceImpl implements TodoService{
@Autowired
private TodoDao dao;
@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);
}
}
📣 Dao
@Repository
public class TodoDao {
@Autowired
private SqlSessionTemplate sqlSession;
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);
}
}
📣 Mapper
<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>