React 를 사용하여 Notes 앱 만들기

JavaScriptBeginner
지금 연습하기

소개

이 프로젝트에서는 React 를 사용하여 간단한 메모 앱을 만들 것입니다. 이 앱을 통해 사용자는 메모를 추가, 편집 및 삭제할 수 있습니다. 개발을 여러 단계로 나누어 각 단계가 특정 요구 사항을 충족하고 필수 기능을 추가하도록 할 것입니다.

👀 미리보기

Notes App

🎯 과제

이 프로젝트에서 다음을 배우게 됩니다.

  • Create React App 명령을 사용하여 새로운 React 프로젝트를 만드는 방법
  • 사용자 인터페이스를 만들기 위해 기능적인 React 컴포넌트를 구축하는 방법
  • React 의 useState 훅을 사용하여 상태를 관리하는 방법
  • 애플리케이션 내에서 메모를 추가하고 관리하는 방법
  • 메모 추가, 편집 및 삭제와 같은 기능을 구현하는 방법
  • React 컴포넌트에서 사용자 상호 작용 및 이벤트를 처리하는 방법
  • CSS 를 사용하여 React 애플리케이션의 스타일을 지정하는 방법
  • 기본적인 CRUD (Create, Read, Update, Delete) 애플리케이션을 개발하는 방법
  • React 프로젝트를 구조화하고 구성하는 방법
  • 메모 앱을 위한 간단하고 반응형 사용자 인터페이스를 구축하는 방법

🏆 성과

이 프로젝트를 완료하면 다음을 수행할 수 있습니다.

  • 새로운 React 프로젝트 설정
  • React 컴포넌트 생성 및 관리
  • 컴포넌트 상태 관리를 위해 useState와 같은 React 훅 사용
  • React 애플리케이션에서 사용자 입력 및 폼 제출 처리
  • props 를 사용하여 부모 및 자식 컴포넌트 간에 데이터와 함수 전달
  • React 에서 반응형 및 대화형 사용자 인터페이스 생성
  • React 애플리케이션 내에서 기본적인 데이터 저장 및 조작 구현
  • React 프로젝트에서 코드 파일 구조화 및 구성
  • React 컴포넌트 스타일 지정을 위해 CSS 사용
  • React 애플리케이션 디버깅 및 문제 해결
  • React 애플리케이션 구축을 위한 모범 사례 따르기
이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 고급 레벨의 실험이며 완료율은 48%입니다.학습자들로부터 83%의 긍정적인 리뷰율을 받았습니다.

프로젝트 설정

요구 사항:

  • 새로운 React 프로젝트에서 종속성 설치.

기능:

  • 필요한 종속성 및 기본 프로젝트 구조로 프로젝트를 초기화합니다.

단계:

  1. 터미널을 열고 프로젝트 폴더로 이동합니다.

    cd notes-app

    이 명령은 project 디렉토리 아래에서 실행해야 합니다.

  2. 프로젝트에 종속성 설치:

    npm install

    설치가 완료되면 node_modules 폴더가 생성됩니다. 존재하지 않는다면 설치가 성공적으로 완료되지 않은 것입니다.

✨ 솔루션 확인 및 연습

Note 컴포넌트 생성

요구 사항:

  • 개별 노트를 나타내는 Note 컴포넌트를 생성합니다.
  • Note 컴포넌트는 노트 내용을 표시하고, 편집 버튼과 삭제 버튼을 제공해야 합니다.

기능:

  • 노트의 제목과 텍스트를 표시합니다.
  • 노트를 편집하고 삭제하기 위한 버튼을 제공합니다.

단계:

  1. src 폴더 내에 Note.js라는 새 파일을 생성합니다.

  2. 다음과 같이 Note 컴포넌트를 구현합니다.

import React from "react";

const Note = ({ note }) => {
  return (
    <div className="note">
      <h3>{note.title}</h3>
      <p>{note.text}</p>
      <button>Edit</button>
      <button>Delete</button>
    </div>
  );
};

export default Note;
✨ 솔루션 확인 및 연습

App 컴포넌트 및 State 생성

요구 사항:

  • 노트와 해당 상태를 관리할 App 컴포넌트를 생성합니다.
  • 노트 배열을 저장하기 위해 상태를 초기화합니다.
  • 노트를 추가, 삭제 및 편집하는 함수를 구현합니다.

기능:

  • 노트 배열을 유지합니다.
  • 새로운 노트를 추가합니다.
  • 노트를 삭제합니다.
  • 노트를 편집합니다.

단계:

  1. src 폴더에서 App.js 파일을 엽니다.

  2. 파일 상단에서 useState 훅을 가져옵니다.

    // App.js
    import React, { useState } from "react";
    import "./App.css";
    import Note from "./Note";
  3. App 컴포넌트 내에서 노트를 추가, 삭제 및 편집하기 위한 초기 상태와 함수를 설정합니다.

// App.js
function App() {
  const [notes, setNotes] = useState([]);
  const [newNote, setNewNote] = useState({ title: "", text: "" });

  const addNote = () => {
    // TODO: Implement addNote function
  };

  const deleteNote = (id) => {
    // TODO: Implement deleteNote function
  };

  const editNote = (id, newText) => {
    // TODO: Implement editNote function
  };

  return <div className="App">{/* App content goes here */}</div>;
}
✨ 솔루션 확인 및 연습

노트 추가 기능 구현

요구 사항:

  • 새로운 노트를 상태에 추가하는 addNote 함수를 구현합니다.
  • 노트에 제목과 텍스트가 있는지 확인합니다.

기능:

  • 새로운 노트를 상태에 추가합니다.
  • 노트를 추가한 후 입력 필드를 지웁니다.

단계:

  1. addNote 함수를 구현합니다.
// App.js
const addNote = () => {
  if (newNote.title && newNote.text) {
    const newId = Date.now().toString();
    setNotes([...notes, { ...newNote, id: newId }]);
    setNewNote({ title: "", text: "" });
  }
};
  1. JSX 에서 onChange 핸들러를 사용하여 입력 값을 캡처하고 상태를 업데이트합니다.
// App.js
return (
  <div className="App">
    <h1>Notes App</h1>
    <div className="note-form">
      <input
        type="text"
        placeholder="Title"
        value={newNote.title}
        onChange={(e) => setNewNote({ ...newNote, title: e.target.value })}
      />
      <textarea
        rows="4"
        cols="50"
        placeholder="Text"
        value={newNote.text}
        onChange={(e) => setNewNote({ ...newNote, text: e.target.value })}
      />
      <button onClick={addNote}>Add Note</button>
    </div>
  </div>
);
✨ 솔루션 확인 및 연습

노트 삭제 기능 구현

요구 사항:

  • "삭제" 버튼을 클릭했을 때 상태에서 노트를 제거하는 deleteNote 함수를 구현합니다.

기능:

  • "삭제" 버튼을 클릭했을 때 상태에서 노트를 삭제합니다.

단계:

  1. deleteNote 함수를 구현합니다.
// App.js
const deleteNote = (id) => {
  const updatedNotes = notes.filter((note) => note.id !== id);
  setNotes(updatedNotes);
};
  1. 노트 삭제를 활성화하기 위해 deleteNote 함수를 Note 컴포넌트에 prop 으로 전달합니다.
// App.js
<div className="App">
  <div className="note-list">
    {notes.map((note) => (
      <Note key={note.id} note={note} onDelete={deleteNote} onEdit={editNote} />
    ))}
  </div>
</div>
✨ 솔루션 확인 및 연습

노트 수정 기능 구현

요구 사항:

  • "수정" 버튼을 클릭했을 때 노트의 텍스트를 업데이트하는 editNote 함수를 구현합니다.

기능:

  • 편집 가능한 텍스트 영역 (textarea) 에 노트 텍스트를 표시합니다.
  • "저장" 버튼을 클릭했을 때 노트의 텍스트를 업데이트합니다.

단계:

  1. editNote 함수를 구현합니다.
// App.js
const editNote = (id, newText) => {
  const updatedNotes = notes.map((note) =>
    note.id === id ? { ...note, text: newText } : note
  );
  setNotes(updatedNotes);
};
  1. 편집을 처리하도록 Note 컴포넌트를 업데이트합니다.
// Note.js
import React, { useState } from "react";
const Note = ({ note, onDelete, onEdit }) => {
  const [isEditing, setIsEditing] = useState(false);
  const [editedText, setEditedText] = useState(note.text);

  const handleEdit = () => {
    setIsEditing(true);
  };

  const handleSave = () => {
    onEdit(note.id, editedText);
    setIsEditing(false);
  };

  return (
    <div className="note">
      <div className="note-header">
        <h3>{note.title}</h3>
        <button onClick={() => onDelete(note.id)}>Delete</button>
      </div>
      {isEditing ? (
        <>
          <textarea
            rows="4"
            cols="50"
            value={editedText}
            onChange={(e) => setEditedText(e.target.value)}
          />
          <button onClick={handleSave}>Save</button>
        </>
      ) : (
        <p>{note.text}</p>
      )}
      {!isEditing && <button onClick={handleEdit}>Edit</button>}
    </div>
  );
};
✨ 솔루션 확인 및 연습

스타일링 (App.css)

요구 사항:

  • 시각적으로 보기 좋은 인터페이스를 위해 앱에 기본적인 스타일을 적용합니다.

기능:

  • 사용자 경험 향상을 위해 앱 컴포넌트에 스타일을 적용합니다.

단계:

  1. App.css 파일을 생성하고 앱 컴포넌트에 기본적인 스타일을 적용합니다. 앱 스타일링을 위해 제공된 CSS 코드를 사용합니다.
body {
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  background-color: #f5f5f5;
  margin: 0;
  padding: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

.container {
  max-width: 800px;
  width: 100%;
  padding: 20px;
  box-sizing: border-box;
}

.header {
  background-color: #343a40;
  color: #fff;
  padding: 20px 0;
  text-align: center;
  font-size: 32px;
  margin-bottom: 20px;
  border-radius: 10px;
}

.note-form {
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  margin-bottom: 20px;
}

.note-form input[type="text"],
.note-form textarea {
  width: 100%;
  padding: 10px;
  margin-bottom: 20px;
  border: none;
  border-bottom: 2px solid #007bff;
  background-color: transparent;
  font-size: 16px;
  transition: border-bottom 0.3s;
}

.note-form input[type="text"]:focus,
.note-form textarea:focus {
  border-bottom: 2px solid #0056b3;
  outline: none;
}

.note-form button {
  background-color: #007bff;
  color: #fff;
  border: none;
  border-radius: 5px;
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.note-form button:hover {
  background-color: #0056b3;
}

.note-list {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  justify-content: center;
}

.note {
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  width: 300px;
  transition:
    transform 0.3s,
    box-shadow 0.3s;
}

.note:hover {
  transform: scale(1.03);
  box-shadow: 0 6px 8px rgba(0, 0, 0, 0.2);
}

.note-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

.note-header h3 {
  margin: 0;
  font-size: 24px;
  color: #007bff;
}

.note-actions {
  display: flex;
  gap: 10px;
}

.note-actions button {
  background-color: #007bff;
  color: #fff;
  border: none;
  border-radius: 5px;
  padding: 5px 10px;
  font-size: 14px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.note-actions button:hover {
  background-color: #0056b3;
}
✨ 솔루션 확인 및 연습

앱 실행

React Notes 앱을 실행하려면:

  1. 터미널 또는 명령 프롬프트를 엽니다.

  2. 프로젝트의 루트 디렉토리 ( package.json 파일이 있는 곳) 에 있는지 확인합니다.

  3. 개발 서버를 시작합니다:

    npm start

    이제 브라우저의 8080 포트에서 기본적인 React 앱이 실행되는 것을 볼 수 있습니다. 이 기본 앱을 기반으로 Notes 앱을 만들 것입니다.

  4. 페이지의 효과는 다음과 같습니다:

    React Notes App demo
✨ 솔루션 확인 및 연습

요약

이 프로젝트에서는 React 를 사용하여 개발을 여러 단계로 나누어 간단한 Notes 앱을 만들었습니다. 프로젝트를 설정하고, 노트에 대한 컴포넌트를 생성했으며, 노트를 추가, 삭제 및 편집하는 기능을 구현하고 기본적인 스타일을 적용했습니다. 이러한 단계를 따르면 기능적인 Notes 앱을 구축하고 요구 사항에 맞게 기능을 확장할 수 있습니다.