Notice
Recent Posts
Recent Comments
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

HYEWON JUNG의 개발일지

20231106 TIL react todolist 만들기 본문

개발일지

20231106 TIL react todolist 만들기

혜won 2023. 11. 5. 21:26

이게... 하드 코딩인가.. 

기능구현은 했지만, 그 순간 뿐.. 과제 힌트를 보고 다시 해봐야지.. 

지금 기능이 구현되긴 한 것..

추가하기르 누르면 만들어지는 카드를 완료를 누르면 내용을 복사해서 Done으로 만들고 취소를 누르면 Done의 내용을 todo로 넣어서 돌리고.. 버튼마다 다 다른 기능넣고.. 대환장 코드..

망한 코드

더보기
import React, { useState } from 'react'
import './Listcard.css'

function Listcard() {

    const [todo, setTodo] = useState([{
        id:0,
        title: 'put title',
        content: 'put content'
    },
    {
        id:1,
        title: 'put title2',
        content: 'put content2'
    },
    ])
    const [title, setTitle] = useState('')
    const [content, setContent] = useState('')

    const [done, setDone] = useState([])

    const contentHandler = (event) => { setContent(event.target.value) }

    const addListBtnEvent =(event) =>{
        event.preventDefault()
        const newlist = {
            id : todo.length +1,
            title: title,
            content,
        };
        setTodo([...todo, newlist])
        setTitle('')
        setContent('')

    };

    const removeListBtnEvetn =(id)=>{
        const newTodo =todo.filter(to=>to.id !== id)
        setTodo(newTodo)

    }
    const DoneListBtnEvent =(id)=>{
       
        const isDone = todo.filter(to=>to.id === id)
        setDone(isDone)
        const newTodo =todo.filter(to=>to.id !== id)
        setTodo(newTodo)

        
        const newdonelist = {
            id : done.length +1,
            title: isDone[0].title,
            content: isDone[0].content,
        };
        setDone([...done, newdonelist])
    }
    const removeDoneListBtnEvetn =(id)=>{
        const newDone =done.filter(to=>to.id !== id)
        setDone(newDone) 
    }
    const cancelDoneBtnEvent = (id)=>{
        const isDone =done.filter(to=>to.id !== id)
        setDone(isDone) 
        const cancelDone = done.filter(to=>to.id === id)
        setTodo(cancelDone)

        const cancledonelist = {
            id : todo.length +1,
            title: cancelDone[0].title,
            content: cancelDone[0].content,
        };
        setTodo([...todo, cancledonelist])

    }


    return (
        <div>

            <header>
                <h1>TO DO LIST</h1>

            </header>
            <form className='inputBox' onSubmit={addListBtnEvent}>
                <div>제목:<input
                    value = {title}
                    onChange={
                        function (event) {
                            setTitle(event.target.value)
                        }
                    } 
                    /></div>

                <div>내용:<input
                    value = {content}
                    onChange={contentHandler} /></div>

                <button >추가</button>
            </form>
            <h2>working</h2>
            <div className='List'>
                {
                    todo.map(function (item) {
                        return (
                            <div key={item.id} className='box'>
                                <h2>{item.title}</h2>
                                <p>{item.content}</p>
                                <button onClick={()=>(removeListBtnEvetn(item.id))}>삭제</button>
                                <button onClick={()=>(DoneListBtnEvent(item.id))}>완료</button>
                            </div>)
                    })
                }
            </div>
            <h2>Done</h2>
            <div className='List'>
                {
                    done.map(function (item) {
                        return (
                            <div key={item.id} className='box2'>
                                <h2>{item.title}</h2>
                                <p>{item.content}</p>
                                <button onClick={()=>(removeDoneListBtnEvetn(item.id))}>삭제</button>
                                <button onClick={()=>(cancelDoneBtnEvent(item.id))} >취소</button>
                            </div>)
                    })
                }
            </div>
            

        </div>


    )
}

export default Listcard

 

 

보기엔 멀쩡해보이는.. 하드코딩
  1. 제목과 내용을 입력하고, [추가하기] 버튼을 클릭하면 Working에 새로운 Todo가 추가되고 제목 input과 내용 input은 다시 빈 값으로 바뀌도록 구성해주세요.
  2. Todo의 isDone 상태가 true이면, 상태 버튼의 라벨을 취소, isDone이 false 이면 라벨을 완료 로 조건부 렌더링 해주세요.
  3. Todo의 상태가 Working 이면 위쪽에 위치하고, Done이면 아래쪽에 위치하도록 구현합니다.
  4. Layout의 최대 넓이는 1200px, 최소 넓이는 800px로 제한하고, 전체 화면의 가운데로 정렬해주세요.

강조되어있는 부분 안지키기.. 

지금 코드는.. 흠.. 그래.. 망한게 분명.. (20231105)

힌트를 봤더니 기능이 두개 ..? 

그렇다면 삭제버튼과 완료취소버튼에 기능이 담긴건데.. 

처음 추가 부분을 빼고는 다 삭제했다.

 

done부분에도 똑같이 todo를 map돌리는데 filter된 map을 돌리면 되지않을까?

isDone 이 false인 경우만 map돌리기

 return (<div className='List'>
        {
            todo
                .filter((item) => {
                    return item.isDone === false
                })
                .map(function (item) {
                    return (
                        <div key={item.id} className='box'>
                            <div className='cardContent'>
                                <h2>{item.title}</h2>
                                <p>{item.content}</p>
                                <p>{item.isDone}</p>
                            </div>
                            <div className='cardBtn'>
                                <button onClick={() => (removeBtn(item.id))}>삭제</button>
                                <button onClick={() => (changeBtn(item.id))}>완료</button>
                            </div>

                        </div>)
                })
        }
    </div>)

isDone이 true인 경우만 map돌리기

return (<div className='List'>
        {
            todo
                .filter((item) => {
                    return item.isDone === true
                })
                .map(function (item) {
                    return (
                        <div key={item.id} className='box'>
                            <div className='cardContent'>
                                <h2>{item.title}</h2>
                                <p>{item.content}</p>
                                <p>{item.isDone}</p>
                            </div>
                            <div className='cardBtn'>
                                <button onClick={() => (removeBtn(item.id))}>삭제</button>
                                <button onClick={() => (changeBtn(item.id))}>취소</button>
                            </div>

                        </div>)
                })
        }
    </div>)

이렇게 하면 삭제버튼기능을 따로 할 것 없이 진행할 수 있다. 

  const removeListBtnEvent = (id) => {
    const newTodo = todo.filter(to => to.id !== id)
    setTodo(newTodo)
  }
  
  return..
   <button onClick={() => (removeBtn(item.id))}>삭제</button>

버튼을 누르면서 버튼에id랑 같지 않은 애들만 필터링해서 내보내기.

  const changeDoneState = (id) => {
    const changeTodo = todo.map((item) => {
      if (id === item.id) {
        return { ...item, isDone: !item.isDone }
      } else {
        return item
      }

    })
    setTodo(changeTodo)
  }

완료취소버튼은 누를 때 isDone의 값이 반전되도록 설정을 했는데 불변성 때문에 map을 돌려서 전개구문해서 isDone부분만 바꿔주기

=> state를 바꿔줘야해서 새로운 배열을 만드는 것임..

기능 구현은 마무리 되었고 인풋의 유효성 검사!

const addListBtnEvent = (event) => {
    event.preventDefault()

    const warning = document.querySelector('.warning')
    const warning2 = document.querySelector('.warning2')

    if ((title === '' || content === '') && (title.length > 15 || content.length > 100)) {
      warning2.classList.add('colorChange')
      warning.classList.add('colorChange')

    } else if (title.length > 15 || content.length > 100) {
      warning.classList.remove('colorChange')
      warning2.classList.add('colorChange')

    } else if (title === '' || content === '') {
      warning2.classList.remove('colorChange')
      warning.classList.add('colorChange')
    } else {
      const newlist = {
        id: todo.length + 1,
        title: title,
        content,
        isDone: false
      };
      setTodo([...todo, newlist])
      setTitle('')
      setContent('')
      warning.classList.remove('colorChange')
      warning2.classList.remove('colorChange')
    }

  };

2023.11.06 - [오류모음] - Cannot read properties of null (reading 'classList')

 

Cannot read properties of null (reading 'classList')

유효성 검사를 진행하는데 계속 첫 새로고침후에 바로 추가하기를 누르면 'Cannot read properties of null (reading 'classList')' 이라는 오류가 계속 뜨는 것이다.. 문제의 코드는 ↓↓ const warning = document.quer

hyewonjung-coding.tistory.com

유효성 검사중에 났던 오류!

완성본

 

++

git에 올리고 컴포넌트를 다른 방식으로 해보려고 다시 코드를 켰는데 왠걸.. 오류가 나고 있었음..

2023.11.07 - [오류모음] - Module not found: Error: Can't resolve './App' in

 

Module not found: Error: Can't resolve './App' in

react 실행 중 마주친 오류 대충 눈으로 읽어봤을 때 './App'이 안 찾아진다는 것 같았다. 내가 건든 것에는 App.jsx를 import하는 게 없었는데 뭐가 문제 일까했다. 암튼 그래서 구글링을 해서 해봤다.

hyewonjung-coding.tistory.com

진짜 심장이 떨어져 버리는 줄 알았다. 다시 안들어가봤으면 다 해놓고 미스낼 뻔 했다. 

컴포넌트 분리를 어떤 식으로 바꿨냐면 

원래 main에 form 컴포넌트 있고 todolist를 working과 done으로 나눠서 컴포넌트를 분리했는데 

 

이런식으로 변경해주었다.

import React from 'react'
import './App.css';
import { useState } from 'react';
import Listcard from './Listcard';
import Input from './Input'


function App() {
  const [todo, setTodo] = useState([])

  return (
    <div className='container'>
      <header>
        <h1>TO DO LIST</h1>
      </header>
      <Input todo={todo} setTodo= {setTodo}/>
      <Listcard todo={todo} setTodo={setTodo}/> 
    </div>
  )
}
// 컴포넌트를 분리할 때 1번부터 2번까지 하나로 하는 게

export default App

App.jsx가 훨씬 깔끔해졌다. 

'개발일지' 카테고리의 다른 글

20231109 TIL  (0) 2023.11.10
20231108 TIL  (0) 2023.11.08
20231103 TIL  (0) 2023.11.03
20231102 TIL  (0) 2023.11.02
20231101 TIL  (0) 2023.11.01