useFileInput Hook

A custom React hook for handling file inputs with validation and error handling.

import { useState, useRef } from "react";

import { useFileInput } from "./useFileInput";

export default function App() {
  const { fileName, error, fileInputRef, handleFileSelect, clearFile } =
    useFileInput({
      accept: "image/*",
      maxSize: 2,
    });

  return (
    <div>
      <input type="file" ref={fileInputRef} onChange={handleFileSelect} />
      {fileName && <p>Selected File: {fileName}</p>}
      {error && <p style={{ color: "red" }}>{error}</p>}
      <button onClick={clearFile}>Clear File</button>
    </div>
  );
}
import { useState, useRef } from "react";

interface UseFileInputOptions {
  accept?: string;
  maxSize?: number;
}

export function useFileInput({ accept, maxSize }: UseFileInputOptions) {
  const [fileName, setFileName] = useState<string>("");
  const [error, setError] = useState<string>("");
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [fileSize, setFileSize] = useState<number>(0);

  const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    validateAndSetFile(file);
  };

  const validateAndSetFile = (file: File | undefined) => {
    setError("");

    if (file) {
      if (maxSize && file.size > maxSize * 1024 * 1024) {
        setError(`File size must be less than ${maxSize}MB`);
        return;
      }

      if (accept && !file.type.match(accept.replace("/*", "/"))) {
        setError(`File type must be ${accept}`);
        return;
      }

      setFileSize(file.size);
      setFileName(file.name);
    }
  };

  const clearFile = () => {
    setFileName("");
    setError("");
    setFileSize(0);
    if (fileInputRef.current) {
      fileInputRef.current.value = "";
    }
  };

  return {
    fileName,
    error,
    fileInputRef,
    handleFileSelect,
    validateAndSetFile,
    clearFile,
    fileSize,
  };
}