다중 파일 업로드 UI는 단일 파일 UI를 반복한다고 해결되지 않는다. 하나의 파일은 완료됐고, 다른 파일은 실패했으며, 나머지는 처리 중일 수 있다. 이 상태를 isLoading 하나로 관리하면 화면이 사용자의 실제 상황을 설명하지 못한다.

이 글은 브라우저 파일 업로드 오류 처리 완전 가이드와 연결된다. 오류를 파일별로 저장해야 진행률 UI도 정확해진다.

상태는 전체 요약과 파일별 상태로 나눈다

전체 요약은 사용자가 작업 흐름을 파악하기 위한 정보다. 총 몇 개 중 몇 개가 끝났고, 몇 개가 실패했는지 보여준다. 파일별 상태는 사용자가 어떤 파일을 다운로드하거나 다시 선택해야 하는지 판단하기 위한 정보다.

const summary = {
  total: items.length,
  done: items.filter((item) => item.status === "done").length,
  failed: items.filter((item) => item.status === "error").length,
  processing: items.filter((item) => item.status === "processing").length
};

이 값은 화면 상단에 간결하게 표시하고, 세부 정보는 파일 카드에 넣는다. 이렇게 나누면 전체 작업이 아직 끝나지 않아도 완료된 파일을 먼저 받을 수 있다.

파일 카드의 상태는 명확한 단어를 쓴다

파일 카드에는 대기 중, 처리 중, 완료, 실패처럼 사용자가 바로 이해할 수 있는 상태가 필요하다. 실패 상태에는 에러 코드보다 행동 가능한 메시지가 더 중요하다. "Canvas 변환 실패"보다 "이 이미지는 브라우저에서 변환할 수 없습니다. 다른 파일을 선택해 주세요."가 낫다.

상태보여줄 정보
pending파일명, 원본 크기
processing현재 처리 중임을 알려주는 표시
done결과 크기, 감소율, 다운로드 버튼
error실패 이유와 다시 선택 안내

다운로드 버튼은 결과가 있을 때만 활성화한다

여러 파일 처리 UI에서 자주 생기는 문제는 아직 결과가 없는 파일에도 다운로드 버튼이 보이는 것이다. 사용자는 버튼을 누를 수 있다고 생각하지만 실제 Blob이 없으면 아무 일도 일어나지 않는다. 버튼의 활성 조건은 상태 문자열이 아니라 실제 결과 객체 존재 여부를 기준으로 삼는 편이 안전하다.

const canDownload = item.status === "done" && item.resultFile;

일괄 다운로드도 마찬가지다. 현재 다운로드 가능한 결과만 묶을 것인지, 모든 파일 처리가 끝난 뒤 제공할 것인지 정책을 정해야 한다. 이미지 압축 도구라면 완료된 파일만 먼저 다운로드할 수 있게 하는 편이 사용자에게 더 빠르다.

취소와 재시도를 나중에 붙일 수 있게 설계한다

처음부터 취소 기능을 만들지 않더라도 상태 구조에는 확장 여지를 남기는 것이 좋다. 파일별 상태 객체가 있으면 특정 파일만 재시도하거나 취소 상태를 추가하기 쉽다. 반대로 전체 로딩 상태 하나로 시작하면 기능이 늘어날수록 조건문이 복잡해진다.

정리

다중 파일 UI의 핵심은 전체 작업과 개별 파일을 분리하는 것이다. 전체 요약은 흐름을 보여주고, 파일 카드는 행동을 가능하게 해야 한다. 이 구조는 이미지 압축, 동영상 자르기, 문서 변환처럼 브라우저 안에서 시간이 걸리는 작업에 공통으로 적용할 수 있다.