본문 바로가기
React

[React] Todo-List 만들기

by teamnova 2025. 6. 9.
728x90

리액트란 무엇일까요?

사용자 인터페이스 (UI)를 만들기 위한 자바스크립트 라이브러리 입니다.

 

1. 사용자 인터페이스: 우리가 웹사이트나 앱에서 보는 모든것, 즉 버튼, 입력창, 메뉴, 사진 등 화면에 보이는 모든 요소를 의미합니다.

2. 자바스크립트 라이브러리: '프레임워크'가 아닌 '라이브러리'라는 점이 중요합니다. 프레임워크가 집을 짓는데 필요한 모든 것(설계도, 규칙, 도구)을 제공하는 '풀세트'라면, 라이브러리는 특정 기능(예: 못을 박는 망치)을 쉽게 사용 할 수 있도록 제공하는 '도구'에 가깝습니다.

 

리액트를 왜 사용할까요?

과거 웹페이지의 특정 부분에는 (예:'좋아요' 숫자)이 바뀌면 페이지 전체를 새로고침 해야했습니다. 요즘 웹사이트는 그렇지 않죠

인스타그램에서도 '좋아요'를 눌러도 페이지 전체가 깜빡이지 않고 하트모양과 숫자만 바뀝니다. 이걸 도와주는 것입니다. 

 

예제코드 

(리액트 설치)
npx create-react-app todo-list

cd todo-list

npm start

 

App.css

body {
  background-color: #f4f4f4;
  font-family: sans-serif;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;
}

.app-container {
  background: white;
  padding: 2rem;
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  width: 400px;
}

h1 {
  text-align: center;
  color: #333;
}

.todo-list {
  margin-top: 1rem;
}

.todo-item {
  background: #fff;
  padding: 0.8rem;
  border-bottom: 1px solid #eee;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.input-container {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.input-container input {
  flex-grow: 1;
  padding: 0.5rem;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.input-container button {
  padding: 0.5rem 1rem;
  border: none;
  background-color: #5C6BC0;
  color: white;
  border-radius: 4px;
  cursor: pointer;
}

.input-container button:hover {
  background-color: #3F51B5;
}
.todo-item.completed span {
  text-decoration: line-through;
  color: #aaa;
}

.todo-item span {
  cursor: pointer;
  flex-grow: 1;
}

.delete-button {
  background-color: #EF5350;
  color: white;
  border: none;
  padding: 0.3rem 0.6rem;
  border-radius: 4px;
  cursor: pointer;
  opacity: 0; /* 평소에는 안보이게 */
  transition: opacity 0.2s;
}

.todo-item:hover .delete-button {
  opacity: 1; /* 마우스를 올리면 보이게 */
}

 

App.js

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

function App() {
  const [todos, setTodos] = useState([
    { id: 1, text: '리액트 공부하기', completed: false },
    { id: 2, text: '블로그에 글 올리기', completed: false },
  ]);
  const [input, setInput] = useState('');

  const addTodo = () => {
    if (input.trim() === '') return;
    const newTodo = {
      id: Date.now(),
      text: input,
      completed: false,
    };
    setTodos([...todos, newTodo]);
    setInput('');
  };

  // 5. 완료 상태를 토글(toggle)하는 함수
  const toggleTodo = (id) => {
    setTodos(
      todos.map(todo =>
        // id가 일치하는 항목을 찾으면,
        // completed 값을 반전시킨 '새로운' 객체를 반환합니다.
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  // 6. 할 일을 삭제하는 함수
  const deleteTodo = (id) => {
    // id가 일치하지 않는 항목들만 모아서 '새로운' 배열을 만듭니다.
    setTodos(todos.filter(todo => todo.id !== id));
  };

  return (
    <div className="app-container">
      <h1>My To-Do List</h1>
      <div className="input-container">
        <input
          type="text"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyPress={(e) => e.key === 'Enter' && addTodo()} // Enter 키로도 추가
          placeholder="새로운 할 일을 입력하세요"
        />
        <button onClick={addTodo}>추가</button>
      </div>

      <div className="todo-list">
        {todos.map(todo => (
          // 7. UI에 기능 연결
          <div
            key={todo.id}
            // completed 상태에 따라 다른 className을 적용
            className={`todo-item ${todo.completed ? 'completed' : ''}`}
          >
            <span onClick={() => toggleTodo(todo.id)}>
              {todo.text}
            </span>
            <button className="delete-button" onClick={() => deleteTodo(todo.id)}>삭제</button>
          </div>
        ))}
      </div>
    </div>
  );
}
export default App;

 

시연영상