2016-10-26 8 views
1

사용자가 파일을 끌어서 파일 정보를 표시 할 수 있도록 react-dropzone 및 React-Redux라는 노드 패키지 모듈을 사용하고 있습니다.파일 항목이로드 된 후 dataTransfer에서 FileList 만 디스패치하는 방법

react-dropzone 구성 요소는 표준 event.dataTransfer.files의 FileList를 제공합니다.

문제는 내가 FileList를 Redux 저장소에 디스패치 할 때 파일 항목이 아직 FileList 배열에로드되지 않았기 때문에 파일 데이터를 전달할 때 단지 {"preview":"blob:file:///f30eafb8-8a77-4402-9111-379590b4a03f"}이 발생한다는 것입니다.

File 항목을 콘솔에 기록하면 볼 때까지 데이터가로드되기 때문에 파일 항목이 잘 표시되지만로드 된 후에 파일 정보를 전달하는 방법을 알 수는 없습니다.

다음은 FileList 배열에서 File 항목 중 하나를 콘솔에 기록하는 경우의 예입니다.

{ 
    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: "" 
} 

나는 문제가 File 객체가 완전히로드되지 단지이다 생각하지만, 데이터가 완전히로드되면 난 단지 액션을 발사 할 수있는 방법을 알아낼 수 없습니다. 누군가가 올바른 길을 가르쳐 줄 수 있을까요?

여기에 반응-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> 
    ); 
    } 
} 

... 그리고 여기에 위의 onDrop 방법에 사용 년대 setFile 방법을 가지고 내 활동 파일입니다 :

// 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]); 
} 

.. 여기에는 그 행동을 다루는 감속기가 있습니다 :

// 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; 
    } 
} 

답변

1

이 문제가있는 사람들은 나를 위해 라고 생각합니다. 문제는 Filelist의 파일이 사실은 파일/Blob이라고 생각하는 것처럼 "일반"JavaScript 개체 "가 아니라는 것입니다.

나는 세부 사항을 잘 모르겠다. 누군가가 설명해 준다면 그것을 좋아할 것이다. 그러나 나는 내가 아는 것이라고 생각한다.은 BLOB에 표준 JS 객체와 같은 키가 없다는 것이다. 단지 Redux 저장소로 밀어 넣고 기대했던 속성의 키 - 값 쌍을 볼 수 없습니다 (lastModified, lastModifiedDate, name, path, preview, size, type, webkitRelativePath).

방금 ​​방울을봤을 때, 그 속성은 React Dropzone에 의해 File/Blob에 특별히 설정된 속성이므로 preview이었습니다. 다른 속성을 보려면 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' 
]; 

아마이 일을 더 나은 방법이 많이있다 그리고 나는 나의 이해는 사람이 더 잘 설명 할 수 있다면 그래서 나는 아직도 그것을 좋아할 것이다 꺼져 확신합니다. 그 동안,이 솔루션은 나를 위해 일했습니다.

또한 MDN's File drag and drop 문서와 같은 더 많은 정보를위한 다른 장소가 있습니다.

+0

로다시를 사용한다면'_.toPlainObject (files [0])'할 수도 있습니다. –

0

나는 동일한 문제가있었습니다. @Imma Smyrnow가 만든 @Mitch Conquer와 주석에 의해 제공된 솔루션을 시도했지만 File 객체 대신 일반 객체를 반환합니다. 또한 here에서 설명한대로 직렬화 할 수없는 객체를 저장하는 것은 좋지 않습니다. 따라서, 내가 한 것은 FileReader를 사용하여 파일을 base64로 먼저 변환하고 저장합니다.

const reader = new FileReader(); 
reader.readAsDataURL(file); 

그리고 나서 here에 의해 제공된 솔루션으로 파일로 다시 변환 한 후.

export const dataURLtoFile = (dataurl, filename) => { 
    var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], 
    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); 
    while(n--){ 
     u8arr[n] = bstr.charCodeAt(n); 
    } 
    return new File([u8arr], filename, {type:mime}); 
}