npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yoonhaemin-lib/use-file-upload

v1.1.3

Published

React hook for file upload with built-in validation (type, size, count, filename length) and custom validations

Downloads

54

Readme

@yoonhaemin-lib/use-file-upload

파일 업로드를 쉽게 관리할 수 있는 React Hook

Features

  • 간단한 API - useState와 유사한 직관적인 인터페이스
  • 유효성 검사 - 파일 타입, 크기, 개수, 파일명 길이 자동 검증
  • 커스텀 검증 - 프로젝트별 요구사항에 맞는 사용자 정의 검증 로직 추가
  • 에러 핸들링 - 각 검증 실패 시 세분화된 에러 상태 제공

Installation

npm install @yoonhaemin-lib/use-file-upload
yarn add @yoonhaemin-lib/use-file-upload
pnpm add @yoonhaemin-lib/use-file-upload

Quick Start

import useFileUpload from '@yoonhaemin-lib/use-file-upload';

function FileUploader() {
  const { files, fileInputProps, inputFor, removeFile } = useFileUpload({
    maxFileCount: 1,
  });

  return (
    <div>
      <button {...inputFor}>파일 선택</button>
      <input {...fileInputProps} style={{ display: 'none' }} />

      {files?.map((file, index) => (
        <div key={index}>
          {file.name}
          <button onClick={() => removeFile(index)}>삭제</button>
        </div>
      ))}
    </div>
  );
}

Usage

기본 사용법

import React from 'react';
import useFileUpload from '@yoonhaemin-lib/use-file-upload';

const BasicExample = () => {
  const { files, fileInputProps, inputFor, removeFile } = useFileUpload({
    maxFileCount: 3,
    size: 5, // MB
    types: ['image/png', 'image/jpeg'],
  });

  return (
    <div>
      <button {...inputFor}>파일 선택</button>
      <input {...fileInputProps} style={{ display: 'none' }} />

      <ul>
        {files?.map((file, index) => (
          <li key={index}>
            {file.name}
            <button onClick={() => removeFile(index)}>삭제</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

에러 핸들링

import React from 'react';
import useFileUpload from '@yoonhaemin-lib/use-file-upload';

const ErrorHandlingExample = () => {
  const { files, fileInputProps, inputFor, removeFile, isError } = useFileUpload({
    types: ['image/png', 'image/jpeg'],
    size: 5,
    maxFileCount: 3,
    limitNameLength: 20,
  });

  return (
    <div>
      <button {...inputFor}>파일 선택</button>
      <input {...fileInputProps} style={{ display: 'none' }} />

      {/* 에러 메시지 표시 */}
      {isError.type && <p style={{ color: 'red' }}>허용되지 않은 파일 형식입니다.</p>}
      {isError.size && <p style={{ color: 'red' }}>파일 크기가 5MB를 초과합니다.</p>}
      {isError.count && <p style={{ color: 'red' }}>최대 3개까지만 업로드 가능합니다.</p>}
      {isError.nameLength && <p style={{ color: 'red' }}>파일 이름이 너무 깁니다. (최대 20자)</p>}

      <ul>
        {files?.map((file, index) => (
          <li key={index}>
            {file.name}
            <button onClick={() => removeFile(index)}>삭제</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

onChange 콜백 사용

import React from 'react';
import useFileUpload from '@yoonhaemin-lib/use-file-upload';

const OnChangeExample = () => {
  const { files, fileInputProps, inputFor } = useFileUpload({
    onChange: (uploadedFiles) => {
      console.log('업로드된 파일:', uploadedFiles);
      // API 호출이나 다른 로직 실행
      // 참고: 유효성 검사를 통과한 파일만 onChange가 호출됩니다.
    },
  });

  return (
    <div>
      <button {...inputFor}>파일 선택</button>
      <input {...fileInputProps} style={{ display: 'none' }} />
    </div>
  );
};

커스텀 검증

import React from 'react';
import useFileUpload from '@yoonhaemin-lib/use-file-upload';

const CustomValidationExample = () => {
  const { files, fileInputProps, inputFor, isError } = useFileUpload({
    customValidations: [
      // 파일 크기가 1KB 미만인지 검증
      (file) => ({ tooSmall: file.size < 1024 }),
      // 파일 이름에 특수문자가 있는지 검증
      (file) => ({ hasSpecialChar: /[!@#$%^&*(),.?":{}|<>]/.test(file.name) }),
    ],
  });

  return (
    <div>
      <button {...inputFor}>파일 선택</button>
      <input {...fileInputProps} style={{ display: 'none' }} />

      {isError.tooSmall && <p>파일 크기가 너무 작습니다. (최소 1KB)</p>}
      {isError.hasSpecialChar && <p>파일 이름에 특수문자를 사용할 수 없습니다.</p>}
    </div>
  );
};

초기 파일 설정

import React from 'react';
import useFileUpload from '@yoonhaemin-lib/use-file-upload';

const InitialFilesExample = () => {
  // 기존에 업로드된 파일이 있는 경우
  const existingFiles = [
    /* File 객체 배열 */
  ];

  const { files, fileInputProps, inputFor, removeFile } = useFileUpload({
    initialFiles: existingFiles,
  });

  return (
    <div>
      <button {...inputFor}>파일 추가</button>
      <input {...fileInputProps} style={{ display: 'none' }} />

      <ul>
        {files?.map((file, index) => (
          <li key={index}>
            {file.name}
            <button onClick={() => removeFile(index)}>삭제</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

API Reference

useFileUpload 매개변수

| 매개변수 | 타입 | 기본값 | 설명 | | ------------------- | ------------------------- | ------ | ----------------------------------------------------------------------------------------- | | types | string[] | - | 허용할 파일 타입 (MIME 타입) | | size | number | 10 | 허용할 최대 파일 크기 (단위: MB) | | maxFileCount | number | 1 | 허용할 최대 파일 개수 | | limitNameLength | number | - | 파일 이름의 최대 길이 | | onChange | (files: File[]) => void | - | 파일이 변경되었을 때 호출될 콜백 함수 (유효성 검사 통과 시에만 호출됨) | | initialFiles | File[] | - | 초기 파일 목록 | | customValidations | ((file: File) => T)[] | - | 커스텀 검증 함수 배열. 각 함수는 { [key: string]: boolean } 형태의 객체를 반환 |

useFileUpload 반환값

| 반환값 | 타입 | 설명 | | ---------------- | --------------------------------------------- | ------------------------------------------------------------------------------- | | files | File[] \| null \| undefined | 현재 선택된 파일 목록 | | fileInputProps | React.InputHTMLAttributes<HTMLInputElement> | <input type="file"> 엘리먼트에 전달할 props (onChange, accept, multiple, ref) | | inputFor | React.HTMLAttributes<HTMLElement> | 파일 선택을 트리거할 커스텀 버튼에 전달할 props (onClick) | | removeFile | (index: number) => void | 특정 인덱스의 파일을 제거하는 함수 | | isError | FileErrorType & T | 각 검증 규칙에 대한 에러 상태 객체 |

FileErrorType

type FileErrorType = {
  size: boolean; // 파일 크기 초과 여부
  count: boolean; // 파일 개수 초과 여부
  type: boolean; // 파일 타입 불일치 여부
  nameLength: boolean; // 파일 이름 길이 초과 여부
};

Examples

이미지 미리보기와 함께 사용

import React, { useState } from 'react';
import useFileUpload from '@yoonhaemin-lib/use-file-upload';

const ImagePreviewExample = () => {
  const [previews, setPreviews] = useState<string[]>([]);

  const { files, fileInputProps, inputFor, removeFile } = useFileUpload({
    types: ['image/png', 'image/jpeg', 'image/gif'],
    maxFileCount: 5,
    onChange: (uploadedFiles) => {
      // 미리보기 URL 생성
      const urls = uploadedFiles.map((file) => URL.createObjectURL(file));
      setPreviews(urls);
    },
  });

  return (
    <div>
      <button {...inputFor}>이미지 선택</button>
      <input {...fileInputProps} style={{ display: 'none' }} />

      <div style={{ display: 'flex', gap: '10px', marginTop: '10px' }}>
        {previews.map((url, index) => (
          <div key={index} style={{ position: 'relative' }}>
            <img src={url} alt={`preview ${index}`} style={{ width: '100px', height: '100px', objectFit: 'cover' }} />
            <button
              onClick={() => {
                removeFile(index);
                setPreviews((prev) => prev.filter((_, i) => i !== index));
              }}
              style={{ position: 'absolute', top: 0, right: 0 }}
            >
              ×
            </button>
          </div>
        ))}
      </div>
    </div>
  );
};

TypeScript

이 패키지는 TypeScript로 작성되었으며 완전한 타입 정의를 제공합니다.

import useFileUpload from '@yoonhaemin-lib/use-file-upload';

// 커스텀 검증의 타입 정의
type CustomValidation = {
  tooSmall: boolean;
  hasSpecialChar: boolean;
};

const { isError } = useFileUpload<CustomValidation>({
  customValidations: [
    (file) => ({ tooSmall: file.size < 1024 }),
    (file) => ({ hasSpecialChar: /[!@#$%^&*()]/.test(file.name) }),
  ],
});

// isError는 FileErrorType & CustomValidation 타입을 가집니다
if (isError.tooSmall) {
  // 타입 안전하게 접근 가능
}

License

MIT © Yoon Hae Min