How to see the content of a file added to upload (drag and drop) in React

Viewed 21

I am using a shared component for uploading files which accepts only application/json, here is the component's code:

import React, { DragEvent, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';

export interface UploadFieldProps extends React.InputHTMLAttributes<HTMLInputElement> {
  label?: string;
  mainErrorMessage?: string;
  subErrorMessage?: string;
  onFilesChange?: (files: FileList | File[] | null) => void;
  multiple?: boolean;
  inputId?: string;
  defaultFiles?: DefaultFiles[];
  route?: string;
  showDelete?: boolean;
  maxSize?: number;
  deleteHandler?: (id: string) => void;
  showDownloadIcon?: boolean;
}

export interface DefaultFiles {
  fileId: string;
  name: string;
}

const MAX_SIZE = 5242880;

interface IFile extends File {
  fileId?: string;
}

export function UploadField({
  className = '',
  inputId = 'upload-input',
  disabled = false,
  label = 'Drag files here or ...',
  mainErrorMessage,
  subErrorMessage,
  multiple = false,
  onFilesChange,
  defaultFiles = [],
  route,
  showDelete = true,
  maxSize = MAX_SIZE,
  deleteHandler,
  showDownloadIcon,
  ...props
}: UploadFieldProps) {
  const [errorMessage, setErrorMessage] = useState('');
  const [files, setFiles] = useState<FileList | File[] | null | Array<File>>(
    defaultFiles as unknown as File[]
  );

  useEffect(() => {
    setFiles(defaultFiles as unknown as File[]);
  }, [defaultFiles]);

  const createDataTransferFiles = (filesChanged: FileList) => {
    const dataTransfer = new DataTransfer();
    setErrorMessage('');
    Array.from(filesChanged).forEach((file) => {
      if (file.size <= maxSize) {
        if (dataTransfer.files.length !== 0) {
          for (const fileData of Array.from(dataTransfer.files)) {
            if (fileData.name !== file.name) {
              dataTransfer.items.add(file);
              break;
            }
          }
        } else {
          dataTransfer.items.add(file);
        }
      } else {
        setErrorMessage(`${file.name} exceeds size limit. 5mb max file size supported.`);
      }
    });
    setFiles([...Array.from(dataTransfer.files), ...(files as [])]);
    return dataTransfer.files;
  };

  const stopDragAndDropDefaultEvent = (e: DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    e.stopPropagation();
  };

  const onDragAndDrop = (e: DragEvent<HTMLDivElement>) => {
    if (disabled) {
      return;
    }
    stopDragAndDropDefaultEvent(e);
    const files = e.dataTransfer.files;
    if (files && files.length) {
      const fileList = createDataTransferFiles(e.dataTransfer.files);
      onFilesChange && onFilesChange(fileList);
    }
  };

  const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    if (event.target.files) {
      const fileList = createDataTransferFiles(event.target.files);
      onFilesChange && onFilesChange(fileList);
    }
  };

  return (
    <div
      className='relative z-0 w-full'
      onDragOver={stopDragAndDropDefaultEvent}
      onDragEnter={stopDragAndDropDefaultEvent}
      onDrop={onDragAndDrop}
    >
      <input
        id={inputId}
        accept='application/JSON'
        type='file'
        data-testid='upload-input'
        className='hidden'
        multiple={multiple}
        disabled={disabled}
        onChange={onChange}
        {...props}
      />
      {label && <label htmlFor='upload-input'>{label}</label>}
      <div>
        <div className='flex items-center'>
          <button disabled={disabled} data-testid='add-file' title='Upload file' />
        </div>
      </div>
      {files?.length !== 0 &&
        <div className='pt-2'>
          {files &&
            Array.from([...(files as unknown as File[])]).map((file, index) => {
              return (
                <div className='flex items-center content-center p-2 mb-3' key={index}>
                  {file?.name && defaultFiles[index]?.fileId ?
                    <Link to={`${route + defaultFiles[index].fileId}`} className='flex font-bold'>
                      {file?.name}
                    </Link>
                    :
                    <span className='pr-8 font-bold'>{file?.name}</span>
                  }
                </div>
              );
            })}
        </div>
      }
      {(!!mainErrorMessage || !!errorMessage) &&
        <div className='flex flex-row ml-2 text-sm text-status-red' id='error'>
          <span className='pr-2 font-bold'>{mainErrorMessage || errorMessage}</span>
          <span>{subErrorMessage}</span>
        </div>
      }
    </div>
  );
}

export default UploadField;

When a file is dropped in that area, it show its name but I cannot find out how to show the content of that file.

As it can be seen, a file has the type File which says:

interface File extends Blob {
    readonly lastModified: number;
    readonly name: string;
    readonly webkitRelativePath: string;
}

Is there a way to show the actual JSON content after drag & drop?

Something like:

  if (files?.length) {
    console.log('File content: ', files[0].something);
  }
0 Answers
Related