노트 폼 렌더링하기

이제 useEffect 메서드를 사용해 노트를 불러오는 컨테이너를 만들었으니, 노트를 수정할 폼을 렌더링해 보겠습니다.

Change indicator src/containers/Notes.tsx의 플레이스홀더 return 문을 다음 코드로 교체하세요.

function validateForm() {
  return content.length > 0;
}

function formatFilename(str: string) {
  return str.replace(/^\w+-/, "");
}

function handleFileChange(event: React.ChangeEvent<HTMLInputElement>) {
  if (event.currentTarget.files === null) return;
  file.current = event.currentTarget.files[0];
}

async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
  let attachment;

  event.preventDefault();

  if (file.current && file.current.size > config.MAX_ATTACHMENT_SIZE) {
    alert(
      `파일 크기는 ${
        config.MAX_ATTACHMENT_SIZE / 1000000
      } MB 이하로 선택해 주세요.`
    );
    return;
  }

  setIsLoading(true);
}

async function handleDelete(event: React.FormEvent<HTMLFormElement>) {
  event.preventDefault();

  const confirmed = window.confirm(
    "이 노트를 삭제하시겠습니까?"
  );

  if (!confirmed) {
    return;
  }

  setIsDeleting(true);
}

return (
  <div className="Notes">
    {note && (
      <Form onSubmit={handleSubmit}>
        <Stack gap={3}>
          <Form.Group controlId="content">
            <Form.Control
              size="lg"
              as="textarea"
              value={content}
              onChange={(e) => setContent(e.target.value)}
            />
          </Form.Group>
          <Form.Group className="mt-2" controlId="file">
            <Form.Label>첨부 파일</Form.Label>
            {note.attachment && (
              <p>
                <a
                  target="_blank"
                  rel="noopener noreferrer"
                  href={note.attachmentURL}
                >
                  {formatFilename(note.attachment)}
                </a>
              </p>
            )}
            <Form.Control onChange={handleFileChange} type="file" />
          </Form.Group>
          <Stack gap={1}>
            <LoaderButton
              size="lg"
              type="submit"
              isLoading={isLoading}
              disabled={!validateForm()}
            >
              저장
            </LoaderButton>
            <LoaderButton
              size="lg"
              variant="danger"
              onClick={handleDelete}
              isLoading={isDeleting}
            >
              삭제
            </LoaderButton>
          </Stack>
        </Stack>
      </Form>
    )}
  </div>
);

Change indicator 이 작업을 완료하기 위해 Notes 컴포넌트 함수 상단의 상태와 참조 선언 아래에 isLoadingisDeleting을 추가하세요.

const [isLoading, setIsLoading] = useState(false);
const [isDeleting, setIsDeleting] = useState(false);

Change indicator const [note, setNote] 정의를 올바른 타입으로 교체하세요.

const [note, setNote] = useState<null | NoteType>(null);

Change indicator src/containers/Notes.css에 다음 스타일을 추가하세요.

.Notes form textarea {
  height: 300px;
  font-size: 1.5rem;
}

Change indicator 마지막으로 필요한 모듈을 임포트하세요.

import config from "../config";
import Form from "react-bootstrap/Form";
import { NoteType } from "../types/note";
import Stack from "react-bootstrap/Stack";
import LoaderButton from "../components/LoaderButton";
import "./Notes.css";

여기서 몇 가지 작업을 수행했습니다:

  1. note 상태 변수가 설정된 경우에만 폼을 렌더링합니다.

  2. 폼 내부에서 note.attachment를 사용해 첨부 파일을 조건부로 렌더링합니다.

  3. 업로드 시 파일명에 추가한 타임스탬프를 제거하고 formatFilename을 사용해 첨부 파일 URL을 포맷합니다.

  4. 사용자가 노트를 삭제할 수 있도록 삭제 버튼을 추가했습니다. 그리고 제출 버튼과 마찬가지로 호출이 진행 중임을 나타내는 플래그가 필요합니다. 이를 isDeleting이라고 합니다.

  5. NewNote 컴포넌트에서와 동일한 방식으로 파일 입력을 통해 첨부 파일을 처리합니다.

  6. 삭제 버튼은 브라우저의 confirm 대화 상자를 사용해 사용자에게 삭제 여부를 확인합니다.

이제 브라우저로 전환하면 노트가 로드된 것을 확인할 수 있습니다.

노트 페이지 로드된 스크린샷

다음으로, 노트에 변경 사항을 저장하는 방법을 살펴보겠습니다.