如何在 React 项目中使用 FileReader 读取本地文件

10,584 阅读2分钟

如何在 React 项目中使用 FileReader 读取本地文件

FileReader 是什么

FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

FileReader 的基本用法

此处展示读取本地文本文件的示例

<--读取本地文件-->
<input type="file" onChange={handleFileReader} />

const handleFileReader = async (e) => {
    try {
      // 获取文件
      const file = e.target.files[0];
      // 实例化 FileReader对象
      const reader = new FileReader();
      reader.onload = function (e) {
        // 在onload函数中获取最后的内容
        setFileContent(e.target.result as string);
      };
      // 调用readerAsText方法读取文本
      reader.readAsText(file);
    } catch (error) {
      console.log(error)
    } 
  };

如何在 React 中使用

在 react 中我们可以封装成一个 hook,使其具有复用性,和提供易用性

创建<input type="file" />示例获取本地文件

由于在实际使用的时候用户其实并不想要在document上挂载<input type="file" /> dom示例,因此我们可以利用createElement在内存中创建该dom示例只利用他的能力而不挂载到document文档

const createFileInput = () => {
  const $fileInput = document.createElement("input");
  $fileInput.type = "file";
  return $fileInput;
};

设计 hook 的入参和出参

在该hook中用户不需要传入任何额外的入参
出参包括文件的文本内容读取错误的错误信息是否正在读取中的状态触发用户选择本地文件的方法
具体的 ts 定义如下

export type Result = {
  // 文件的文本内容
  fileContent: string;
  // 是否正在读取中的状态
  isReading: boolean;
  // 读取错误的错误信息
  error: any;
  trigger: () => void;
};

核心代码编写

完整代码

import React, { useState, useRef } from "react";

export type Result = {
  fileContent: string;
  isReading: boolean;
  error: any;
  trigger: () => void;
};

const createFileInput = () => {
  const $fileInput = document.createElement("input");
  $fileInput.type = "file";
  return $fileInput;
};

const useTextFileReader = (): Result => {
  const [fileContent, setFileContent] = useState<string>("");
  const [isReading, setIsReading] = useState<boolean>(false);
  const [error, setError] = useState<any>(null);

  const fileInputRef = useRef(createFileInput());

  const handleFileReader = async (e) => {
    setIsReading(true);
    try {
      const file = e.target.files[0];
      const reader = new FileReader();
      reader.onload = function (e) {
        setFileContent(e.target.result as string);
      };
      reader.readAsText(file);
    } catch (error) {
      setError(error);
    } finally {
      setIsReading(false);
    }
  };

  fileInputRef.current.onchange = handleFileReader;

  const trigger = () => {
    fileInputRef.current.click();
  };

  return {
    fileContent,
    isReading,
    error,
    trigger,
  };
};

export default useTextFileReader;