2017-09-21 1 views
0

다음 파일 선택기 대화 상자가 있습니다. 여러 파일 선택을 허용하고 싶습니다. 파일을 선택한 후에는 선택한 파일의 미리보기를 렌더링하고 싶습니다. 내 코드는 다음과 같습니다 그러나자바 스크립트에서 읽은 Synchronos 파일

<input 
      type="file" 
      multiple 
      accept=".png, .jpeg" 

      onChange={e => { 
      this.setState({ previews: [] }); 

      if (!e.target.files) { 
       return; 
      } 

      var previews = []; 

      for (var i = 0; i < e.target.files.length; i++) { 
       var file = e.target.files[i]; 
       (function(file, previews) { 
       var reader = new FileReader(); 

       reader.onload = function(e) { 
        // console.log(e.target.result); 
        console.log("Just pushed a new preview"); 
        previews.push(e.target.result); 
       }; 
       reader.readAsDataURL(file); 
       })(file, previews); 
      } 

      console.log("All files read"); 
      // I want this to be called only after 
      // all the file contents are read 
      this.setState({ previews }); 
      }} 
     /> 

, 위의 코드와 함께, All files read 콘솔에 인쇄 한 후 내 Just pushed a new preview가 인쇄됩니다.

FileReader 루프 (클로저)를 끝내고 this.setState({previews})을 호출 할 수있는 방법이 있습니까?

모든이 코드는 중요하다면 반응 파일에 있습니다.

+0

주 스레드를 차단하지 않는 것처럼 비동기입니다. 그러면 파일 크기에 따라 페이지가 응답하지 않을 수 있습니다. 그래서 그 페이지에서 허용되지 않습니다. 그러나 (FileReaderSync) [https://developer.mozilla.org/en-US/docs/Web/API/FileReaderSync]는 'workers'에서 액세스 할 수 있습니다. – Panther

+0

모든 파일을 읽은 경우'onLoad' 콜백에 체크를 추가하고'set previews'를 추가 할 수 있습니다. – Panther

+0

'onLoad' 콜백에서 모든 파일이 읽혔는지 어떻게 알 수 있습니까? 나는 onLoad 콜백에'i' 또는'e.target.files.length'를 넘길 방법이 없습니다. 인덱스와 전체 길이를 전달하는 방법을 찾더라도 모든 파일을 읽을 수 있음을 신뢰할 수 없습니다. 읽은 다섯 번째 파일은 세 번째 파일 읽기 전에 끝날 수도 있습니다. 아니면 다른 방법이 있습니까? –

답변

0

onLoad 이벤트 내에서 setState를 이동해야합니다. 파일 판독기가 비동기 적이기 때문에 onLoad 외부에 상태를 설정하면 이벤트가 완료되기 전에 트리거되므로 previews 배열이 비어 있거나 불완전하게됩니다.

var previews = []; 
var s = this; 

for (var i = 0; i < e.target.files.length; i++) { 
    var file = e.target.files[i]; 
     var reader = new FileReader(); 

     reader.onload = function(e) { 
     previews.push(e.target.result); 
     s.setState({ previews }); 
     }; 

     reader.readAsDataURL(file); 
} 
+0

스레드가 안전하지 않습니까? 두 개의 다른 스레드가 미리보기를 잘못된 값으로 병렬로 설정할 수 있습니까? –

+0

@SankarP 아니요. 메소드 내부의 로컬 미리보기 배열이 추가되고 복사본이 상태로 유지 관리되기 때문에 불가능합니다. 게다가, js로 작업 할 때 쓰레드 처리가 덜 중요합니다. – Fawaz

+0

@SankarP fyr : https://stackoverflow.com/questions/12163175/push-to-array-safely-how-to-worry-or-not – Fawaz

1

Promise.all을 사용하여 모든 파일이 처리되었는지 여부를 확인하기 위해 모든 약속이 완료 될 때까지 기다립니다. 또한 파일을 읽는 즉시 상태를 업데이트해야합니다. 업데이트를 위해 진행률 막대 및 setState를 추가하는 것이 더 좋습니다.

var Sample = React.createClass({ 
    getInitialState: function() { return { previews: [], allfilesdone:false }; }, 
    render: function() { 
    var p = this.state.previews.map((p) => <div>{p}</div>); 
    return (
     <div style = {this.styler}> 
     <input id="upload" multiple 
      accept=".txt" type="file" 
      onClick={(e) => this.setState({allfilesdone: false})} 
      onChange={(event)=> { 
       var s = this; 
       this.setState({previews:[], allfilesdone: false}); 
       var fs = event.target.files; 
       Promise.all([...fs].map((file) => { 
        var reader = new FileReader(); 
        return new Promise((resolve,reject) => { 
        reader.onload = (ev) => { 
         resolve(ev.target.result); 
         var pt = this.state.previews; 
         pt.push(ev.target.result); 
         s.setState({previews: pt}); 
        } 
        reader.readAsText(file); 
        }); 
       })) 
        .then(ft => { 
         this.setState({allfilesdone: true}); 
         }); 
      }}/> 
     <div>all processed: {this.state.allfilesdone?"true":"false"}</div> 
     <div>number of files: {this.state.previews.length}</div> 
     <div>{p}</div> 
     </div> 
    ); 
    } 
}); 

React.render(
    <Sample />, 
    document.getElementById('mount-point')); 
+0

나는 개념을 보여주기 위해 텍스트 파일을 사용했습니다. 이미지 용으로 변경할 수 있습니다. 원하는대로 readAsText를 수정하십시오. –

+0

감사합니다. 이것이 제가하려고 한 것입니다. 그러나 나는 결심을 놓치고 있었기 때문에 나는 약속을 얻지 못했다. 부름을 거부한다. 감사. 이는 허용 된 응답보다 스레드로부터 안전한 접근입니다 (JS가 브라우저에서 단일 스레드 인 경우에만 작동합니다). –

관련 문제