패스트캠퍼스 데브캠프 41일차 [React, 메모장]

Su Min·2024년 7월 17일
0
post-thumbnail

useState 사용해서 메모장 구현하기

폴더 구조

  • App.js
  • components
    • Header.js
    • AddItem.js
    • Item.js
    • List.js

App.js

최근 실시간 강의때 민태강사님께 배웠던 예전 리액트 라우팅 방식도 사용해보고 싶어서 아직은 단일 페이지인 메모장에 도입해보았다.

import "./App.css"
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"
import { useState } from "react"
import { Header } from "./components/Header"
import { List } from "./components/List"
import { AddItem } from "./components/AddItem"

const App = () => {
  const date = new Date()
  const currentDate = date.toISOString().substring(0, 10)
  const [todays, setTodays] = useState(currentDate)
  const [addItem, setAddItem] = useState(false)
  const [title, setTitle] = useState("")
  const [content, setContent] = useState("")
  const [label, setLabel] = useState("Memo")
  const [notes, setNotes] = useState([
    {
      id: 1,
      label: "Memo",
      title: "벨로그 내용",
      content: "하루에 공부한 내용 정리하면서 복습하고 업로드하기",
      todays: "2024.07.14",
    }
  ])

  const handleToday = () => { // 오늘 날짜 출력 함수
    setTodays(currentDate)
  }

  const deleteItem = (id) => { // 메모 삭제 함수
    let newNotes = notes.filter((item) => item.id !== id)
    setNotes(newNotes)
  }
  const addItemModal = () => { // 메모 추가하는 모달 띄우기 함수
    addItem ? setAddItem(false) : setAddItem(true)
    if (addItem) { // 초기화
      setTitle("")
      setContent("")
      setLabel("Memo")
    }
  }
  const handleTitle = (e) => {
    setTitle(e.target.value)
  }
  const handleContent = (e) => {
    setContent(e.target.value)
  }
  const handleLabel = (e) => {
    setLabel(e.target.value)
  }
  const addNote = (e) => { // 메모 추가 함수
    e.preventDefault()
    if (title !== "" && content !== "") {
      const newNote = { id: crypto.randomUUID(), label, title, content, todays }
      const newNotes = [...notes, newNote]
      setNotes(newNotes)
      addItemModal()
    }
  }

  return (
      <main>
        {addItem ? (
          <AddItem
            addNote={addNote}
            title={title}
            content={content}
            handleContent={handleContent}
            handleTitle={handleTitle}
            handleLabel={handleLabel}
            addItemModal={addItemModal}
            todays={todays}
            handleToday={handleToday}
          />
        ) : null}
        <Router>
          <Routes>
            <Route path="/" element={<Header addItemModal={addItemModal} />}>
              <Route index element={<List notes={notes} deleteItem={deleteItem} addItemModal={addItemModal} />} />
            </Route>
          </Routes>
        </Router>
      </main>
  )
}
export default App

Route path="/" 인 부분에 Header컴포넌트가 들어가고 List컴포넌트를 감쌌다. Header컴포넌트에 있는 Outlet 부분엔 감싸진 element 요소(List)가 자리하게 된다.

Header.js

import { ReactComponent as AddIcons } from "../assets/add-icon.svg"
import { ReactComponent as SearchIcon } from "../assets/search-icon.svg"
import { Outlet } from "react-router-dom"
import "./Header.css"

export const Header = ({ addItemModal }) => {
  return (
    <>
      <header>
        <div>
          <SearchIcon />
          <input placeholder="Search" />
        </div>
        <button onClick={() => addItemModal()}>
          <AddIcons />
          <span>Add</span>
        </button>
      </header>
      <h1>Your notes</h1>
      <Outlet /> // Route의 element 공간
    </>
  )
}

List.js

메모장 리스트 생성 컴포넌트

import "./List.css"
import { Item } from "./Item"

export const List = ({ notes, deleteItem, addItemModal }) => {
  return (
    <ul>
      {notes.map((item) => {
        return <Item 
    	item={item} 
    	key={item.id} 
    	deleteItem={deleteItem} 
    	addItemModal={addItemModal} 
    	/>
      })}
    </ul>
  )
}

Item.js

메모 생성 컴포넌트

import "./Item.css"
import { ReactComponent as DeleteIcon } from "../assets/delete-icon.svg"
import { ReactComponent as EditIcon } from "../assets/edit-icon.svg"

export const Item = ({ item, deleteItem, addItemModal }) => {
  return (
    <li>
      <div>
        <span className={item.label}>{item.label}</span>
        <div>
          <button>
            <EditIcon onClick={() => addItemModal()} />
          </button>
          <button>
            <DeleteIcon onClick={() => deleteItem(item.id)} />
          </button>
        </div>
      </div>
      <p>{item.title}</p>
      <p>{item.content}</p>
      <span className="today">{item.todays}</span>
    </li>
  )
}

AddItem.js

메모 추가 컴포넌트

import "./AddItem.css"

export const AddItem = ({
  todays,
  handleToday,
  addNote,
  title,
  content,
  handleContent,
  handleTitle,
  handleLabel,
  addItemModal,
}) => {
  
  return (
    <form onSubmit={addNote}>
      <div>
        <p onChange={handleToday}>{todays}</p>
        <div>
          <label htmlFor="Memo">
            <input type="radio" name="label" id="Memo" value="Memo" onChange={handleLabel} defaultChecked />
            <span>Memo</span>
          </label>
          <label htmlFor="Home">
            <input type="radio" name="label" id="Home" value="Home" onChange={handleLabel} />
            <span>Home</span>
          </label>
        </div>
        <div className="titleWrap">
          <p>제목</p>
          <input type="text" value={title} onChange={handleTitle} />
        </div>
        <div className="contentWrap">
          <p>내용</p>
          <textarea type="text" value={content} onChange={handleContent} />
        </div>
        <div>
          <button type="submit">추가</button>
          <button onClick={() => addItemModal()}>취소</button>
        </div>
      </div>
    </form>
  )
}

추가 버튼에 submit타입을 넣고 폼태그에 onSubmit이벤트를 준다. 각 value는 label, title, content이고 onChange 핸들러는 각각의 state를 업데이트한다.

결과

profile
성장하는 과정에서 성취감을 통해 희열을 느낍니다⚡️

0개의 댓글

관련 채용 정보