TodoList
-MiniGame - TodoList(state, map, context개념)
배열을 map을 이용해서 추가 해보자~
add를 누르면 Todo List에 추가
Delete를 누르면 삭제
→ context이용하는게 편할 듯~
-스프레드 문법
key : todos[todos.length-1].key+1
todos.length-1
: 현재 todos
배열의 마지막 항목을 가리킵니다.
todos[todos.length-1].key+1
: 현재 todos
배열의 마지막 항목의 key
값에 1을 더한 값입니다.
원래 table의 정석은 html에서는 tbody와 thead가 생략 가능
그러나 리액트에서는 기능상에는 오류가 안 나지만 콘솔창에서 오류
Ex12TodoContext.jsx
import { Context, createContext } from "react";
export const TodoContext = createContext(null)
Ex12.jsx
import React, { useState } from 'react'
import { TodoContext } from './context/Ex12TodoContext'
import List from './components/Ex12/List'
import AddItem from './components/Ex12/AddItem'
import './ex12.css'
const Ex12 = () => {
/** 할 일 리스트가 누적되어있는 배열(state 형식) */
const[todos,setTodos] = useState([
{text : '물 마시기', completed : false, key : 1}
]);
// Step 1. 할 일 추가하기
const [newTodo, setNewTodo] = useState("")
/** 새로운 newTodo 데이터를 todos 배열에 추가하는 함수 */
const handelNewTodoAddition = () => {
console.log('hanelNewTodoAddition function',newTodo);
setTodos([
...todos,
{text : newTodo,
completed: false,
key : todos[todos.length-1].key+1
}
]);
setNewTodo("")
}
/** todolist를 삭제시켜 줄 함수 */
const handleTodoDelete = (delkey) => {
console.log('handleTodoDelete',delkey);
const filteredList = todos.filter(item => item.key !== delkey)
setTodos(filteredList)
}
/** 완료한 할 일에 체크 혹은 반대의 경우 체크 해제 toggle 함수 */
const handleTodotoggle = (ckkey) => {
console.log('handleTodotoggle function',ckkey);
//* find 배열함수
// 내가 조건을 걸면 그 애가 있는지 찾아 줌 ckkey 와 같은 것을 찾아줌
let targetTodo = todos.find(item => item.key == ckkey)
console.log('targetTodo',targetTodo);
if(targetTodo){
// 내 안에 있는 것의 반대의 것을 넣어줌
targetTodo.completed = !targetTodo.completed
// 바뀌지 않는 것의 세팅을 그대로..?
setTodos([...todos])
}
}
return (
<TodoContext.Provider value={{todos,newTodo,
setNewTodo,
handelNewTodoAddition,
handleTodoDelete,
handleTodotoggle}}>
<div className='todo-container'>
<h1>🎀 TODO LIST 🎀</h1>
<List/>
<AddItem/>
</div>
</TodoContext.Provider>
)
}
export default Ex12
List.jsx
import React, { useContext } from 'react'
import { TodoContext } from '../../context/Ex12TodoContext'
import ListItem from './ListItem';
const List = () => {
const {todos} = useContext(TodoContext)
console.log('todos',todos);
return (
<div>
{/* 반복하는 것은 table이 아니라 tr */}
<table>
<tbody>
{/* todos라는 함수를 가져와서 map함수를 돌릴거야
ListItem이라는 컴포넌트를 배열에 있는 갯수만큼 띄어줄거야 */}
{/* context는 몇번째 배열이 나올줄 모르므로 props로 보내주기 */}
{todos.map(item => <ListItem key={item.key} todo={item}/>)}
</tbody>
</table>
</div>
)
}
export default List
ListItem.jsx
import React, { useContext } from 'react'
import { TodoContext } from '../../context/Ex12TodoContext'
const ListItem = ({todo}) => {
const{todos,handleTodoDelete,handleTodotoggle} = useContext(TodoContext)
console.log(todos);
return (
<>
<tr>
<td>
<input
type='checkbox'
//체크여부
checked={todo.completed}
// 바뀔때 마다 onChange(토글) 함수 사용할거야
onChange={()=>{handleTodotoggle(todo.key)}}
></input>
</td>
<td>
<label
style={{
textDecoration : todo.completed ? "line-through" : "none"
}}>
<span className = 'todo-text' >
{/* props로 받아옴 */}
{todo.text}
</span>
</label>
</td>
<td>
{/* 매개함수 쓸려면 익명함수 안에 넣어야함 */}
<button onClick={()=>{handleTodoDelete(todo.key)}} >Delete</button>
</td>
</tr>
</>
)
}
export default ListItem
AddItem.jsx
import React from 'react'
import { TodoContext } from '../../context/Ex12TodoContext'
import { useContext } from 'react'
const AddItem = () => {
const{newTodo, setNewTodo, handelNewTodoAddition} = useContext(TodoContext)
return (
<div>
<input
// value를 newTodo로 지정해줌으로 써 input창 리셋
value={newTodo}
type='text' onChange={(e) => {setNewTodo(e.target.value)}}/>
<button onClick={handelNewTodoAddition}>Add</button>
</div>
)
}
export default AddItem
이벤트 함수 → 익명함수
ex12.css
@font-face {
font-family: "GmarketSansMedium";
src: url("https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2001@1.1/GmarketSansMedium.woff")
format("woff");
font-weight: normal;
font-style: normal;
}
* {
font-family: "GmarketSansMedium";
}
.todo-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-image: linear-gradient(120deg, #f1f087 0%, #fffeef 100%);
border-radius: 20px;
margin: 3%;
padding: 10%;
box-sizing: border-box;
}
h1 {
font-weight: 900;
}
li {
list-style: none;
}
button {
height: 30px;
font-size: 0.8em;
background-color: #f0ee7a;
border: 0px;
}
input[type="checkbox"] {
margin: 3%;
}
li{
display: flex;
align-items: center;
justify-content: center;
}
.todo-text{
/* background-color: red; */
width: 300px;
display: block;
}
.list-container{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
input[type="text"]{
width: 300px;
}