본문 바로가기

CodeSoom- React 13기

[코드숨] 리액트 13기 -2강/ 과제2 - 간단한 Todo App 만들기

▼ index.jsx 중간 제출 (파일나누기전 전체)

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

function TodoForm({ onSubmit }) {
  const [todoText, setTodoText] = useState('');
  const handleChange = (e) => setTodoText(e.target.value);

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!todoText) {
      // eslint-disable-next-line no-alert
      //밑에 alert에 대해 ESLint 비활성화하려면 위에꺼 작성
      alert('할 일을 입력해 주세요😀');
      return;
    }
    if (onSubmit) {
      onSubmit(todoText);
    }
    setTodoText('');
  };
  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="할 일을 입력해주세요."
          onChange={handleChange}
          value={todoText}
        />
        <button type="submit">추가</button>
      </form>
    </div>
  );
}

function Todos({ todoItems, onClick }) {
  if (todoItems.length === 0) {
    return (
      <p>
        할 일이 없어요! 🙅‍♀️
      </p>
    );
  }
  return (
    <ol>
      {
        todoItems.map(({ id, todo }) => (
          <Todo
            key={id}
            id={id}
            text={todo}
            onClick={() => onClick(id)}
          />
        ))
      }
    </ol>
  );
}

function Todo({ text, onClick }) {
  return (
    <li>
      <span>{text}</span>
      <button type="button" onClick={onClick}>완료</button>
    </li>
  );
}

function TodoPage({
  onSubmit, todoItems, onClick,
}) {
  return (
    <div>
      <p>assignment2</p>
      <h3>To-do</h3>
      <TodoForm
        onSubmit={onSubmit}
      />
      <Todos todoItems={todoItems} onClick={onClick} />
    </div>
  );
}

function App() {
  const [todoItems, setTodoItems] = useState([]);

  const handleSubmit = (todoItem) => {
    setTodoItems([
      ...todoItems, {
        id: Date.now(),
        todo: todoItem,
      },
    ]);
  };

  const handleDelete = (todoId) => {
    setTodoItems(
      todoItems.filter((item) => item.id !== todoId),
    );
  };
  // Array.filter() 조건에 해당하는 걸 남겨서 배열로 return해줌 /누른 item의 id와 id가 같지않은걸 배열로 남겼기 때문에 해당 클릭한 id꺼만 지워짐

  return (
    <TodoPage onSubmit={handleSubmit} todoItems={todoItems} onClick={handleDelete} />
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('app'),
);

 

 

▼ 화면구현


리뷰받고 수정 제출2

0. import React from 'react'리액트17 버전 이후부터는 생략이 가능

생략하고 babel.config.js 수정함

방법:지난번 블로그 참고

라이브러리 import 와 로컬 파일 구분하기 위해 띄어주기

import { useState } from 'react';

import TodoForm from './TodoForm';

1.

▼ 기존 코드에서   if (onSubmit) {..  if 조건문 불필요

 const handleSubmit = (e) => {
    e.preventDefault();
    if (!todoText) {
      // eslint-disable-next-line no-alert
      //밑에 alert에 대해 ESLint 비활성화하려면 위에꺼 작성
      alert('할 일을 입력해 주세요😀');
      return;
    }
    if (onSubmit) {
      onSubmit(todoText);
    }
    setTodoText('');
  };

 

▼ 아래와 같이 수정

 if (!todoText) {
 ...
 }
    onSubmit(todoText); //if제외
    setTodoText('');
 ..

 

2. props drilling해결하기

 

해결: App.jsx에서 선언했던 state,함수를 TodoPage.jsx로 옮겼다.

 

3. TodoForm.jsx 에서 함수를 선언하고 관리했는데 이를 수정하는 작업이 필요

 

해결: TodoForm.jsx를 아래와 같이 변경하고,

기존 코드를 TodoPage.jsx 에서 관리되도록 옮겨 수정함

 

아래는 수정한 전체 제출 코드

 TodoForm

function TodoForm({
  onSubmit,
  todoText,
  handleChange,
}) {
  const handleSubmit = (e) => {
    e.preventDefault();
    onSubmit(todoText);
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="할 일을 입력해주세요."
          onChange={handleChange}
          value={todoText}
        />
        <button type="submit">추가</button>
      </form>
    </div>
  );
}
export default TodoForm;

 

▼ TodoPage.jsx

import { useState } from 'react';

import TodoForm from './TodoForm';
import Todos from './Todos';

function TodoPage() {
  const [todoItems, setTodoItems] = useState([]);

  const [todoText, setTodoText] = useState('');

  const handleChange = (e) => setTodoText(e.target.value);

  const handleSubmit = (todoItem) => {
    if (!todoText) {
      alert('할 일을 입력해 주세요😀');
      return;
    }

    setTodoItems([
      ...todoItems, {
        id: Date.now(),
        todo: todoItem,
      },
    ]);

    setTodoText('');
  };

  const handleDelete = (todoId) => {
    setTodoItems(
      todoItems.filter((item) => item.id !== todoId),
    );
  };

  return (
    <div>
      <p>assignment2</p>
      <h3>To-do</h3>
      <TodoForm
        onSubmit={handleSubmit}
        todoText={todoText}
        handleChange={handleChange}
      />
      <Todos todoItems={todoItems} onClick={handleDelete} />
    </div>
  );
}

export default TodoPage;

 


리뷰받고 수정 제출3

1. App이 여러 페이지로 구성되어 있지 않으므로 TodoPage.jsx를 없애고 App으로 내용을 넘겨줌

 

2. TodoForm.jsx에서 아래의 handleSubmit 함수를 제거하고 App.jsx로 옮겨 관리하게 수정

f

 

해결: App.jsx 에서 아래와 같이 코드 수정(매개변수를 받아오는 것이 아닌, todoText를 직접설정해주자 적용됨)

const handleSubmit = (e) => {
    e.preventDefault();
    if (!todoText) {
      alert('할 일을 입력해 주세요😀');
      return;
    }

    setTodoItems([
      ...todoItems, {
        id: Date.now(),
        todo: todoText,
      },
    ]);

    setTodoText('');
  };

리뷰받고 수정 제출4

+handle~, on~ 구분을 통해 실제 일을 '처리'하는 관점과 '사용'하는 입장에서 바라볼 때의 의도를 각각 드러내줄 수 있다.


▼ 최종 전체 코드

index.jsx

import ReactDOM from 'react-dom';

import App from './App';

ReactDOM.render(
  <App />,
  document.getElementById('app'),
);

 

App.jsx

import { useState } from 'react';

import TodoForm from './TodoForm';
import Todos from './Todos';

function App() {
  const [todoItems, setTodoItems] = useState([]);

  const [todoText, setTodoText] = useState('');

  const handleChange = (e) => {
    setTodoText(e.target.value);
  };

  const handleSubmit = (e) => {
    e.preventDefault();

    if (!todoText) {
      // eslint-disable-next-line no-alert
      alert('할 일을 입력해 주세요😀');
      return;
    }

    setTodoItems([
      ...todoItems, {
        id: Date.now(),
        todo: todoText,
      },
    ]);

    setTodoText('');
  };

  const handleDelete = (todoId) => {
    setTodoItems(
      todoItems.filter((item) => item.id !== todoId),
    );
  };

  return (
    <div>
      <p>assignment2</p>
      <h3>To-do</h3>
      <TodoForm
        onSubmit={handleSubmit}
        onChange={handleChange}
        todoText={todoText}
      />
      <Todos todoItems={todoItems} onClick={handleDelete} />
    </div>
  );
}

export default App;

 

TodoForm.jsx

function TodoForm({
  onSubmit,
  onChange,
  todoText,
}) {
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          type="text"
          placeholder="할 일을 입력해주세요."
          onChange={onChange}
          value={todoText}
        />
        <button type="submit">추가</button>
      </form>
    </div>
  );
}
export default TodoForm;

 

Todos.jsx

import Todo from './Todo';

function Todos({ todoItems, onClick }) {
  if (todoItems.length === 0) {
    return (
      <p>
        할 일이 없어요! 🙅‍♀️
      </p>
    );
  }
  return (
    <ol>
      {
        todoItems.map(({ id, todo }) => (
          <Todo
            key={id}
            id={id}
            text={todo}
            onClick={() => onClick(id)}
          />
        ))
      }
    </ol>
  );
}

export default Todos;

 

Todo.jsx

function Todo({ text, onClick }) {
  return (
    <li>
      <span>{text}</span>
      <button type="button" onClick={onClick}>완료</button>
    </li>
  );
}

export default Todo;

할 일을 입력해서 등록하고, 완료할 수 있는 간단한 To-do 리스트를 만들어주세요.

기능 구현

  • 사용자는 할 일을 입력할 수 있습니다.
  • 사용자는 추가 버튼을 눌러서 할 일을 추가할 수 있습니다.
  • 사용자는 할 일 목록을 볼 수 있습니다.
  • 사용자는 완료 버튼을 눌러 할 일을 삭제할 수 있습니다.

제한 조건

  • if는 사용할 수 있어도 else 사용하실 수 없습니다. GuardClauses 방법을 사용해주세요.
  • switch는 사용하실 수 없습니다.
  • let은 사용하실 수 없습니다. const만을 사용하여 문제를 해결해주세요.
  • 함수 이름과 변수 이름에 줄임말은 사용하실 수 없습니다. 길더라도 명확하게 써주세요.
  • indent(인덴트, 들여쓰기) depth를 1로 유지해주세요. 예를 들어, for문 안에 if문이 있으면 indent depth는 2입니다. depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 됩니다.

요구사항

  • ESLint를 돌린 결과 아무런 문제가 없어야 합니다.
  • 모든 인수 테스트를 통과시켜야 합니다.
  • 한 파일에는 하나의 컴포넌트만 있어야 합니다.

Hint

과제를 위해선 반드시 아래 2개의 문서를 읽어주세요.