如何在加载文件项后仅从 dataTransfer 调度 FileList

Mit*_*uer 5 drag-and-drop data-transfer filelist reactjs redux

我使用名为react-dropzone 和React-Redux 的Node 包模块来允许用户将文件拖到窗口上并显示文件信息。

React-dropzone 组件为我提供了标准event.dataTransfer.files中的 FileList 。

我遇到的问题是,当我将该 FileList 分派到 Redux 存储时,File 项尚未加载到 FileList 数组中,因此当我分派 File 数据时,我只是得到{"preview":"blob:file:///f30eafb8-8a77-4402-9111-379590b4a03f"}.

如果我将文件项记录到控制台,它们显示得很好,因为它们的数据在我查看时已加载,但我不知道如何仅在加载后分派文件信息。

下面是当我将 FileList 数组中的一个文件项记录到控制台时所看到的示例。

{
  lastModified: 1473709614000,
  lastModifiedDate: Mon Sep 12 2016 12:46:54 GMT-0700 (PDT),
  name: "test_image.jpg",
  path: "/Users/mitchconquer/Desktop/test_image.jpg",
  preview: "blob:file:///0fe69686-125d-464a-a0a8-a42e497d3808",
  size: 41805,
  type: "image/jpeg",
  webkitRelativePath: ""
}
Run Code Online (Sandbox Code Playgroud)

我相信问题只是文件对象未完全加载,但我无法找到一种方法来仅在数据完全加载后才触发操作。有人能指出我正确的道路吗?

这是我使用react-dropzone的组件:

// FileDrop.js
import React, { Component, PropTypes } from 'react';
import { Link } from 'react-router';
import styles from './Home.css';
import Dropzone from 'react-dropzone';

export default class FileDrop extends Component {
  static propTypes = {
    message: PropTypes.string.isRequired,
    setFile: PropTypes.func.isRequired
  };

  onDrop(files, event) {
    console.log({files});
    this.props.setFile(files);
  }

  render() {
    return (
      <div>
        <Dropzone onDropAccepted={this.onDrop.bind(this)} multiple={false} disablePreview={false}>
          <div>{this.props.message}</div>
        </Dropzone>
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

...这是我的操作文件,其中包含setFile上述方法中使用的方法onDrop

// actions/files.js
export const SET_FILE = 'SET_FILE';

// ACTION CREATORS

function _setFile(file) {
  return {
    type: SET_FILE,
    file
  };
}

// ACTION CREATOR CREATORS

export function setFile(file) {
  return _setFile(file[0]);
}
Run Code Online (Sandbox Code Playgroud)

...这是处理该操作的减速器:

// reducers/files.js
import { SET_FILE } from '../actions/files';

export const initialState = [];

export default function files(state = initialState, action = {}) {
  switch (action.type) {
    case SET_FILE:
      const newState = state.slice();
      const file = action.file;
      newState.push(file);
      return newState;
    default:
      return state;
  }
}
Run Code Online (Sandbox Code Playgroud)

Mit*_*uer 4

对于那些遇到这个问题的人来说,对我来说,我认为问题在于文件列表中的文件并不是像我想象的那样是“普通的 JavaScript 对象”,但实际上是文件/Blob。

我不确定细节 - 如果有人能解释它们,我会很高兴 - 但我认为我知道的是 blob 没有像标准 JS 对象那样的键,所以你不能只是推送它到 Redux 存储并查看它们我期望的属性的键值对 ( lastModified, lastModifiedDate, name, path, preview, size, type, webkitRelativePath)。

如果您只查看 blob,它们唯一的属性是 ,preview因为这是 React Dropzone 专门在 File/Blob 上设置的属性。要查看其他属性,您必须调用 blob 上的每个属性。

这是我下面的解决方案的简化版本。我接收 Filelist 数组,创建一个新对象来设置键值并迭代每个键,并使用该newFile对象的属性来设置它。最后我返回那个对象。然后,您可以在商店中设置该对象,它将具有处理文件所需的数据。

onDrop(files) {
    const fileBlob = files[0];
    const newFile = {};
    _fileProperties.forEach(key => {
      newFile[key] = fileBlob[key];
    });

   return newFile;
}

const _fileProperties = [
  'lastModified',
  'lastModifiedDate',
  'name',
  'path',
  'preview',
  'size',
  'type',
  'webkitRelativePath'
];
Run Code Online (Sandbox Code Playgroud)

可能有很多更好的方法可以做到这一点,我确信我的理解是错误的,所以如果有人能更好地解释这一点,我仍然会喜欢它。与此同时,这个解决方案对我有用。

还有其他一些地方可以提供更多信息,例如MDN 的文件拖放文章。