[React] Todo-List 만들기

찌끅·2024년 8월 21일

Todo-List 만들기

이 코드는 React를 사용하여 Todo List 애플리케이션을 만드는 예제이다. 유데미에 한입 크기로 잘라 먹는 리액트 강의에서 나오는 프로젝트이다.

1. App.jsx: 애플리케이션의 메인 컴포넌트

App.jsx는 전체 애플리케이션의 중심이다. 여기에서 모든 주요 상태를 관리하고, 다른 컴포넌트에 필요한 데이터를 전달하며, 할 일 목록의 생성, 업데이트, 삭제와 같은 주요 기능을 정의한다.

function App() {
  const [todos, setTodos] = useState([]);
  const idRef = useRef(0);

  const onCreate = (content) => {
    const newTodo = {
      id: idRef.current++,
      isDone: false,
      content: content,
      date: new Date().getTime(),
    };

    setTodos([newTodo, ...todos]);
  };

  const onUpdate = (targetId) => {
    setTodos(
      todos.map((todo) =>
        todo.id === targetId ? { ...todo, isDone: !todo.isDone } : todo
      )
    );
  };

  const onDelete = (targetId) => {
    setTodos(todos.filter((todo) => todo.id !== targetId));
  };

  return (
    <div className="App">
      <Header />
      <Editor onCreate={onCreate} />
      <List todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
    </div>
  );
}

export default App;
  • 상태관리 (useState):

    • todos: 할 일 목록을 관리하는 상태이다. 초기값은 빈 배열([])이며, 사용자가 할 일을 추가할 때마다 배열에 새로운 할 일이 추가된다.
  • ID 관리 (useRef):

    • idRef: 할 일에 고유한 ID를 부여하기 위한 참조이다. useRef를 사용하여 값이 변경될 때 컴포넌트가 리렌더링되지 않도록 한다. idRef.current를 통해 현재 ID 값을 가져오고, 새로운 할 일을 추가할 때마다 이 값을 증가시킨다.
  • 할 일 생성 (onCreate):

    • content: 사용자가 입력한 할 일의 내용이다.
    • 이 함수는 새로운 할 일 객체를 생성하고, 해당 객체를 todos 배열의 맨 앞에 추가한다. 여기서 할 일 객체는 고유 ID, isDone 상태, content, 생성 날짜(date)를 포함한다.
  • 할 일 업데이트 (onUpdate):

    • targetId: 업데이트할 할 일의 ID이다.
    • 이 함수는 특정 할 일의 isDone 상태를 토글한다. todos.map()을 사용하여 모든 할 일을 순회하고, targetId와 일치하는 할 일을 찾아 isDone 값을 반전시킨다. 이를 통해 할 일이 완료되었는지 여부를 쉽게 관리할 수 있다.
  • 할 일 삭제 (onDelete):

    • targetId: 삭제할 할 일의 ID이다.
    • 이 함수는 todos.filter()를 사용하여 주어진 ID와 일치하지 않는 모든 할 일들만 남겨서 새로운 배열을 생성한다. 이 배열이 todos로 업데이트되어, 화면에서 해당 할 일이 제거된다.

2. Header.jsx: 헤더 컴포넌트

Header.jsx는 애플리케이션의 상단에 위치하며, 오늘의 날짜와 함께 제목을 표시하는 역할을 한다. 이 컴포넌트는 주로 사용자가 현재 날짜를 쉽게 확인할 수 있도록 돕는 단순한 UI 요소를 제공한다.

import './Header.css';

const Header = () => {
  return (
    <div className="Header">
      <h3>오늘은 📅</h3>
      <h1>{new Date().toDateString()}</h1>
    </div>
  );
};

export default Header;
  • 현재 날짜 표시:
    • new Date().toDateString(): 현재 날짜를 문자열로 변환하여 표시한다. toDateString() 메서드는 날짜를 'Wed Aug 21 2024'와 같은 형식으로 변환해 준다.

3. Editor.jsx: 할 일 입력 및 생성 컴포넌트

Editor.jsx는 사용자가 새로운 할 일을 입력하고 추가할 수 있는 UI 컴포넌트이다. 할 일 추가 시 필요한 여러 가지 입력 및 유효성 검사를 처리한다.

import { useRef, useState } from 'react';
import './Editor.css';

const Editor = ({ onCreate }) => {
  const [content, setContent] = useState('');
  const contentRef = useRef();

  const onChangeContent = (e) => {
    setContent(e.target.value);
  };

  const onKeyDown = (e) => {
    if (e.keyCode === 13) {
      onSubmit();
    }
  };

  const onSubmit = () => {
    if (content === '') {
      contentRef.current.focus();
      return;
    }
    onCreate(content);
    setContent('');
  };

  return (
    <div className="Editor">
      <input
        ref={contentRef}
        value={content}
        onChange={onChangeContent}
        onKeyDown={onKeyDown}
        placeholder="새로운 Todo..."
      />
      <button onClick={onSubmit}>추가</button>
    </div>
  );
};

export default Editor;
  • 상태 관리 (useState):

    • content: 사용자가 입력한 텍스트를 관리하는 상태이다. 사용자가 입력 필드에 텍스트를 입력하면 onChangeContent 함수가 호출되어 이 상태를 업데이트한다.
  • 참조 (useRef):

    • contentRef: 입력 필드를 참조하기 위한 변수이다. 할 일을 추가할 때 내용이 비어 있으면 이 참조를 통해 입력 필드에 포커스를 줄 수 있다.
  • 할 일 추가 (onSubmit):

    • 이 함수는 사용자가 입력한 내용이 비어 있는지 확인하고, 비어 있을 경우 입력 필드에 포커스를 다시 맞춘다. 그렇지 않으면 onCreate 함수를 호출하여 새로운 할 일을 생성하고, 입력 필드를 초기화 한다.
    • 또한, 사용자가 Enter 키를 누르면 onKeyDown 이벤트 핸들러가 onSubmit을 호출하여 할 일이 추가되도록 한다.

4. List.jsx: 할 일 목록 컴포넌트

List.jsx는 할 일 목록을 필터링하여 화면에 표시하는 컴포넌트이다. 검색 기능을 포함하여, 사용자가 할 일을 쉽게 찾을 수 있도록 돕는다.

import { useState } from 'react';
import './List.css';
import TodoItem from './TodoItem';

const List = ({ todos, onUpdate, onDelete }) => {
  const [search, setSearch] = useState('');

  const onChangeSearch = (e) => {
    setSearch(e.target.value);
  };

  const getFilteredData = () => {
    if (search === '') {
      return todos;
    }
    return todos.filter((todo) => {
      return todo.content.toLowerCase().includes(search.toLowerCase());
    });
  };

  const filteredTodos = getFilteredData();

  return (
    <div className="List">
      <h4>Todo List 🌱</h4>
      <input
        value={search}
        onChange={onChangeSearch}
        placeholder="검색어를 입력하세요"
      />
      <div className="todos-wrapper">
        {filteredTodos.map((todo) => {
          return (
            <TodoItem
              key={todo.id}
              {...todo}
              onUpdate={onUpdate}
              onDelete={onDelete}
            />
          );
        })}
      </div>
    </div>
  );
};

export default List;
  • 상태 관리 (useState):

    • search: 사용자가 입력한 검색어를 관리하는 상태이다. 이 상태를 기반으로 할 일 목록을 필터링한다.
  • 검색 기능:

    • onChangeSearch: 검색어가 변경될 때마다 호출되어 search 상태를 업데이트한다.
  • 필터링 기능:

    • getFilteredData: 이 함수는 todos 배열을 검색어에 따라 필터링한다. 검색어가 비어있으면 모든 할 일을 반환하고, 그렇지 않으면 검색어를 포함하는 할 일들만 반환한다.
  • 할 일 목록 렌더링:

    • 필터링된 할 일 목록을 순회하며 각 할 일에 대해 TodoItem 컴포넌트를 렌더링한다. TodoItem에는 각 할 일의 상태(isDone), 내용(content), 날짜(date), ID 등이 전달되며, 업데이트 및 삭제 함수도 함께 전달된다.

5. TodoItem.jsx: 개별 할 일 컴포넌트

TodoItem.jsx는 각각의 할 일을 개별적으로 관리하며, 할 일의 상태 변경 및 삭제 기능을 제공한다.

import './TodoItem.css';

const TodoItem = ({ id, isDone, content, date, onUpdate, onDelete }) => {
  const onChangeCheckbox = () => {
    onUpdate(id);
  };

  const onClickDeleteButton = () => {
    onDelete(id);
  };

  return (
    <div className="TodoItem">
      <input
        onChange={onChangeCheckbox}
        readOnly
        checked={isDone}
        type="checkbox"
      />
      <div className="content">{content}</div>
      <div className="date">{new Date(date).toLocaleDateString()}</div>
      <button onClick={onClickDeleteButton}>삭제</button>
    </div>
  );
};

export default TodoItem;
  • 상태 변경 (onUpdate):

    • 사용자가 체크박스를 클릭할 때 onChangeCheckbox 함수가 호출되어, onUpdate를 통해 상위 컴포넌트(App)에 상태 변경을 요청한다.
    • onUpdateApp.jsx에서 할 일의 isDone 상태를 토글하여 완료 상태를 관리한다.
  • 삭제 기능 (onDelete):

    • 삭제 버튼이 클릭되면 onClickDeleteButton 함수가 호출되어, onDelete를 통해 할 일이 삭제된다.
    • 삭제 요청 역시 App.jsx로 전달되며, todos 배열에서 해당 할 일이 제거된다.

전체 흐름 요약

  1. 사용자가 할 일을 입력하면 Editor.jsx에서 이를 처리하고, onCreate 함수를 통해 새로운 할 일을 생성한다.
  2. 새로운 할 일이 생성되면 App.jsxtodos 상태에 추가된다.
  3. 할 일 목록은 List.jsx에서 필터링되어 표시되며, 검색 기능을 통해 사용자는 특정 할 일을 쉽게 찾을 수 있다.
  4. 사용자는 할 일의 완료 상태를 토글하거나, 삭제할 수 있으며, 이때 App.js에서 상태가 업데이트되고 목록이 갱신된다.

0개의 댓글