SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine(コードジン) DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

現場で役立つ! React向けライブラリ詳説

ドラッグ&ドロップで簡単にファイルが選択できる「react-dropzone」を解説

現場で役立つ! React向けライブラリ詳説 第9回

受け入れ可能なファイル形式を制限する

 続いて、ファイル形式の制限に関する機能を解説します。

 「画像ファイルだけをアップロードしたい」や「PDFファイルとEPUBだけを受け入れたい」といった要求仕様に応える機能は、冒頭で解説したaccept属性によって実現されています。ダイアログによるファイル選択であれば、「acceptで指定した形式のファイルしか選べない」という挙動になるので、受け入れないファイルについて考える必要はないのですが、ドラッグ&ドロップの場合は受け入れできないファイルがドロップされる可能性も考慮する必要があるので、いくつかのインターフェースが追加されています(リスト4)。

[リスト4]受け入れ可能なファイル形式に関する引数や戻り値(src/MyDropzoneStyled.js)
const {
  getRootProps,
  getInputProps,
  // (5) 受け入れ済みのファイル一覧
  acceptedFiles,
  // (6) 受け入れできなかったファイル一覧
  fileRejections,
} = useDropzone({
  // (1) 受け入れ可能なファイル形式を指定する
  accept: "image/*",
  // (2) ドロップされたときのコールバック
  onDrop: (acceptedFiles, fileRejections) => {},
  // (3) 受け入れ可能なファイルがドロップされたときのコールバック
  onDropAccepted: (acceptedFiles) => {},
  // (4) 受け入れできないファイルがドロップされたときのコールバック
  onDropRejected: (fileRejections) => {},
});

 まずはinput要素と同様に、(1)でパラメータとしてacceptに受け入れ可能なファイル形式を指定します。application/jsonのようなMIME Type文字列でも構いませんし、.jpgのような拡張子でも構いません。また、カンマ区切りで複数のファイル形式を指定することもできます。詳しくはMDNをご覧ください。

 受け入れ可能なファイル形式が指定された状態でドラッグ&ドロップを行うと、ファイルは 受け入れができたファイル一覧であるacceptedFilesと 受け入れできなかったファイル一覧であるfileRejectionsに仕分けされます。

 両方のファイル一覧をコールバックで受け取れるのが、リスト3でも言及した(2)のonDropです。また、片方ずつ受け取りたい場合のコールバックとして、(3)のonDropAcceptedと(4)のonDropRejectedがあります。

 フックの戻り値にも(5)のacceptedFilesや(6)のfileRejectionsがあるので、UIにファイル名を表示したい場合には、これらを扱うとよいでしょう。実際の使い方の例として、リスト3にファイル形式の制限を設定したのがリスト5です。

[リスト5]ファイル形式の制限を利用した例(src/MyDropzoneBasicRejectable.js)
export function MyDropzoneBasicRejectable() {
  const onDrop = useCallback((acceptedFiles, fileRejections) => {
    console.log({ acceptedFiles, fileRejections }); // (2)
  }, []);
  const {
    getRootProps,
    getInputProps,
    acceptedFiles, fileRejections, // (3)
  } = useDropzone({
    onDrop,
    accept: "image/*" // (1)
  });

  return (
    <div>
      <div {...getRootProps()}>
        <input {...getInputProps()} />
        <p>
          ファイルをここにドラッグアンドドロップするか、クリックしてファイルを選択してください
        </p>
      </div>
      {acceptedFiles.length > 0 || fileRejections.length > 0 ? ( // (4)
        <ul>
          <li>受け入れられたファイル数: {acceptedFiles.length}</li>
          <li>受け入れできなかったファイル数: {fileRejections.length}</li>
        </ul>
      ) : null}
    </div>
  );
}

 (1)で画像ファイルを受け入れられるように設定しました。(2)でonDropから受け取ったfileRejectionsをコンソールに出力しています。UI上でも結果が見やすいように、(3)でacceptedFilesfileRejectionsを取り出し、(4)でそれぞれのファイル数を表示しています。実際に、PDFファイル、JPEGファイル、CSVファイルをドラッグ&ドロップしたのが図7です。

図7:ファイル形式を制限した場合の受け入れ結果
図7:ファイル形式を制限した場合の受け入れ結果

 JPEGファイル1つが受け入れられ、PDFファイルとCSVファイルは受け入れられなかったことがわかります。この例ではテキストとして表示しましたが、受け入れられなかったファイルについて再選択を促すようなモーダルを表示したりするのもいいかもしれません。

受け入れ可能なファイル数を制限する

 受け入れ可能なファイル形式の話題と似た話題として、受け入れ可能なファイル数も設定できます。一度にアップロードできるファイル数には限りがあるケースもあるので、こういった機能も重要ですね。フックのパラメータとしてmaxFilesを指定することで設定できます(リスト5)。

[リスト5]受け入れ可能なファイル数を指定する
useDropzone({
  // (1) 受け入れ可能なファイル数を指定する
  maxFiles: 3,
});

 (1)で最大3個として指定しているので、このファイル数以下であれば、すべてのファイルがacceptedFilesに入ります。一方で、このファイル数を超えると、すべてのファイルがfileRejectionsに入ります。ファイル数を制限したい場合に使うとよいでしょう。

スタイルを設定する

 さて、最後にドラッグ&ドロップできる領域をもう少し格好よくする方法について解説しておきましょう(リスト6)。

[リスト6]ドラッグ&ドロップ領域にスタイルを付ける(src/MyDropzoneStyled.js)

// (1) 外枠の基本スタイル
const baseStyle = {
  flex: 1,
  display: "flex",
  flexDirection: "column",
  alignItems: "center",
  padding: "20px",
  borderWidth: 2,
  borderRadius: 2,
  borderColor: "#eeeeee",
  borderStyle: "dashed",
  backgroundColor: "#fafafa",
  color: "#bdbdbd",
  outline: "none",
  transition: "border .24s ease-in-out",
};

// (2) フォーカスが当たったときの枠の色
const focusedStyle = {
  borderColor: "#2196f3",
};

// (3) 受け入れ可能なファイルをドラッグしたときの色
const acceptStyle = {
  borderColor: "#00e676",
};

// (4) 受け入れできないファイルをドラッグしたときの色
const rejectStyle = {
  borderColor: "#ff1744",
};

export function MyDropzoneStyled() {
  const {
    getRootProps,
    getInputProps,
    isFocused, // (5) フォーカス中にtrue
    isDragAccept, // (6) 受け入れ可能なファイルをドラッグしたときにtrue
    isDragReject, // (7) 受け入れできないファイルをドラッグしたときにtrue
  } = useDropzone({ accept: "image/*" });

  //(8)状態に応じたスタイルオブジェクトを生成する
  const style = useMemo(
    () => ({
      ...baseStyle,
      ...(isFocused ? focusedStyle : {}),
      ...(isDragAccept ? acceptStyle : {}),
      ...(isDragReject ? rejectStyle : {}),
    }),
    [isFocused, isDragAccept, isDragReject]
  );

  return (
    <div>
      <div {...getRootProps({ style })}>{/* (9)スタイルを適用する */}
        <input {...getInputProps()} />
        <p>
          ファイルをここにドラッグアンドドロップするか、クリックしてファイルを選択してください
        </p>
      </div>
    </div>
  );
}

 (1)では基本の状態を定義します。背景を少し灰色にして、内側には少しpaddingをつけました。また、外枠を破線にしつつ、角を少し丸めました。これだけで図8の見た目になります。

図8:基本の見た目
図8:基本の見た目

 次に、状態に応じて外枠の色が変わるようにしてみましょう。クリックやタブキー入力などで、領域にフォーカスが当たった場合は(2)のスタイルで青くします。受け入れ可能なファイルがドラッグされた(マウスオーバーされた)場合には(3)のスタイルで緑にします。受け入れできないファイル形式がドラッグされた場合には(4)のスタイルで赤にします。

 上記の状態に対応した戻り値がuseDropzoneには用意されています。フォーカス中には(5)のisFocusedがtrueになります(図9)。受け入れできるファイルがドラッグされた場合には(6)のisDragAcceptがtrueになり(図10)、受け入れできないファイルだった場合には(7)のisDragRejectがtrueになります(図11)。状態ごとに色が変わるように(8)でスタイルを切り替え、(9)でスタイルを当てています。

図9:フォーカス中
図9:フォーカス中
図10:受け入れできるファイルをドラッグ中
図10:受け入れできるファイルをドラッグ中
図11:受け入れできないファイルをドラッグ中
図11:受け入れできないファイルをドラッグ中

 さほど複雑なコードを書かずに、こういったリッチなUIを実現できるのは、うれしいところですね。

まとめ

 容易にドラッグ&ドロップ可能なファイル選択UIを提供できる、react-dropzoneについて解説しました。次回はステートマシンによる状態管理とビジュアライズが魅力的なXStateについて解説します。お楽しみに。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
現場で役立つ! React向けライブラリ詳説連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 中川 幸哉(ナカガワ ユキヤ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/15759 2022/04/15 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー