React #07 TodoList 실습

장서영·2023년 12월 12일
0

React

목록 보기
7/12

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;
  }

profile
영이의 일상은 짱셔요

0개의 댓글