🔭

react-dropzone-vv のご紹介

2024/09/02に公開

react-dropzoneの後継packageを作成しており、開発開始から2ヶ月ほど経って仕様が固まってきたので紹介します。

react-dropzone-vvというpackage名で、以下のリンクからドキュメントにアクセスできます。

ドキュメント

https://react-dropzone-vv.yosidev.com/

GitHub

https://github.com/yosipy/react-dropzone-vv

モチベーション

同じ機能を提供するpackageとしてはreact-dropzoneが有名でしょう。私も業務、個人開発の両方でお世話になってきました。しかし、2024年現在、2年近く更新が止まっており、今後のメンテナンスが継続されそうにありません。

そこでreact-dropzoneと同じ機能を作成することにし、packageとして公開しました。

特徴

react-dropzone-vvはファイルの選択にだけ集中し、選択されたファイルなどの状態を保持しません。これによってpackageはシンプルな実装を保つことができ、ユーザーは自由度の高い使い方ができます。

react-dropzoneの多くの機能をカバーしています。accept, disabled, multiple, noClick, noDragなどの指定はもちろん、onDragEnter, onDragOver, onDragLeave, onDrop, onSelect, onErrorなどのコールバック関数も用意されてます。

https://react-dropzone-vv.yosidev.com/introduction/hooks-and-components.html

また、reactのバージョンは17以上に対応しています。古いバージョンの対応予定は無いです。これによってpackage自体のコードは、昔のreactを知らない人でも読みやすいと思います。

使い方

ドキュメントに詳しく書いてあるので、そちらをご覧ください。ここでは簡単にご紹介します。コード全体は以下のようになります。

import { FC, useState } from "react"
import {
  useReactDropzoneVV,
  ReactDropzoneVV,
  RejectedClassifiedFile,
  OnSelectProps,
} from "react-dropzone-vv"

export const Basic: FC = () => {
  const [acceptedFiles, setAcceptedFiles] = useState<File[]>([])
  const [fileRejections, setFileRejections] = useState<
    RejectedClassifiedFile[]
  >([])

  const reactDropzoneVV = useReactDropzoneVV()

  const handleSelect = (props: OnSelectProps) => {
    setAcceptedFiles(props.acceptedFiles)
    setFileRejections(props.fileRejections)
  }

  const handleError = (e: Error) => {
    console.log(e)
  }

  return (
    <section style={{ border: "solid", padding: "1rem" }}>
      <ReactDropzoneVV
        reactDropzoneVV={reactDropzoneVV}
        onSelect={handleSelect}
        onError={handleError}
      >
        <div
          style={{
            padding: "2rem",
            border: "dashed",
            backgroundColor: reactDropzoneVV.isDragging ? "#737373" : "#404040",
          }}
        >
          <p>Drag & drop some files here, or click to select files</p>
        </div>
      </ReactDropzoneVV>

      <div>acceptedFiles</div>
      <ul>
        {acceptedFiles.map((acceptedFile, index) => (
          <li key={index}>{acceptedFile.name}</li>
        ))}
      </ul>
      <div>fileRejections</div>
      <ul>
        {fileRejections.map((fileRejection, index) => (
          <span key={index}>
            <li>{fileRejection.file.name}</li>
            <ul>
              <li>{fileRejection.rejectedCode}</li>
            </ul>
          </span>
        ))}
      </ul>
    </section>
  )
}

ドラッグアンドドロップなどで選択されたファイルを保持するstateを作成しています。

  const [acceptedFiles, setAcceptedFiles] = useState<File[]>([])
  const [fileRejections, setFileRejections] = useState<
    RejectedClassifiedFile[]
  >([])

useReactDropzoneVVはドラッグ中などのstateを保持したり、input要素のrefを保持するのに使われています。

  const reactDropzoneVV = useReactDropzoneVV()

ReactDropzoneVVコンポーネントに渡します。デフォルトでファイルの選択はクリックから選択とドラッグアンドドロップで選択できますが、onSelectはどちらで選択されたときも実行されるコールバック関数です。基本的にはonSelectを使用します。

      <ReactDropzoneVV
        reactDropzoneVV={reactDropzoneVV}
        onSelect={handleSelect}
        onError={handleError}
      >

その他にaccept, disabled, multiple, noClick, noDragなどを指定できます。acceptはmdnの仕様と同じで、拡張子やmimeタイプをカンマ切りで指定できます。

https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/accept

accept="image/png,.webp"

ドキュメントにはこの他にも、複数のデモとコード例を用意しています。

https://react-dropzone-vv.yosidev.com/examples/basic-example.html

おまけの技術的な話

使用している技術一覧

  • vite
  • vitepress ドキュメント作成
  • vitest テスト
  • typescript

依存関係が少ないのでこんな感じです。viteとvitepressを使用したpackage開発は別で記事にしています。この2つを組み合わせた開発体験は良かったです。

https://noh.ink/articles/IrS1eXp2dc8kMhyzcD1A

https://noh.ink/articles/DrVLoQ0rsYKGVmUJEW74

https://noh.ink/articles/5CDV3XNFUny2C3ieS0v0

https://noh.ink/articles/5azsqR0Vc27BbPPXAd9u

Discussion