在React JS中上传文件

时间:2017-11-24 07:15:55

标签: javascript reactjs

通过使用React JS上传文件,我遇到了一个奇怪的问题。

主要组成部分如下:

class Test extends React.Component {
        constructor(props){
        super(props);

      this.state = {
            files: [
                {file_type: registrationFormFields.ID_CARD.key, values: {active: false, fileName: language.btnIdCard, file: null, base64: ""}},
                {file_type: registrationFormFields.STATUTES.key, values: {active: false, fileName: language.btnStatut, file: null, base64: ""}},
                {file_type: registrationFormFields.BLANK_LETTER_HEAD.key, values: {active: false, fileName: language.btnBlanco, file: null, base64: ""}},
                {file_type: registrationFormFields.COMPANY_PHOTO.key, values: {active: false, fileName: language.btnCompanyPhoto, file: null, base64: ""}}
            ]
        };
    }


    handleFiles(file_type, event){
        event.preventDefault();
        let self = this;
        let fileValue = event.target.value;
        let files = "";


        let file = event.target.files[0];
        let filename = file.name.substr(0, file.name.lastIndexOf('.')) || file.name;
        const size_in_mb = file ? file.size/1000000 : null;


        if(this.fileIsValid(file_type, size_in_mb)){
            if(fileValue){
                this.getBase64(file, function(e){
                    let base64 = e.target.result;
                    let nState = self.state.files;

                    if(self.state.files.some(i => i.file_type === file_type))
                        nState = self.state.files.filter(f => f.file_type !== file_type);

                    files = [...nState, {file_type: file_type, values: {active: true, fileName: filename, file, base64: base64}}];

                    self.setState({files: files});
                });

            }
        }
    }

    removeFile = (file_type, file_name) => {
        let nState = this.state.files;
        let nFiles = this.state.files;

        if(this.state.files.some(i => i.file_type === file_type)){
            nState = this.state.files.filter(f => f.file_type !== file_type);
            nFiles = [...nState, {file_type: file_type, values: {active: false, fileName: file_name, file: null, base64: ""}}];

        }
        this.setState({files: nFiles});
    };

  render(){
        return (
        <FileInputButton pictureIcon="credit-card"
                         onFileChange={this.handleFiles.bind(this, registrationFormFields.ID_CARD.key)}
                         btnName="idCard"
                         extraClass="col-lg-offset-2 col-md-offset-2 col-sm-offset-2"
                         fileType={registrationFormFields.ID_CARD.key}
                         fileName={language.btnIdCard}
                         removeFile={this.removeFile}
                         errors={this.state.errors[registrationFormFields.ID_CARD.key]}
                         values={this.getValues(registrationFormFields.ID_CARD.key)}/>
      )
    }
}

React.render(<Test />, document.getElementById('container'));

还有更多代码,但这是重要的代码。

FileInputButton组件如下:

const FileInputButton = ({extraClass, pictureIcon, btnName, onFileChange, values, removeFile, fileType, fileName, errors}) => {

    const name = values.fileName === fileName ? `Add ${fileName}` :  `Added ${fileName}`;
    const icon = values.active ? "check" : "upload";

    let borderClass = "";
    if(values.active) borderClass = "fileSuccess";
    if(errors) borderClass = "fileError";


    let removeButton = "";
    if(values.active){
        removeButton = <div className="remove-file" onClick={() => removeFile(fileType, fileName)}><Ionicon icon="ios-close" fontSize="22px" color={styles.errorColor}/> Remove</div>
    }

    let added_file = "";
    if(values.active){
        added_file = <div className="added-file-name"><Ionicon icon="ios-checkmark" fontSize="22px" color={styles.successColor}/>{values.file.name}</div>
    }

    return (
        <div className={`col-lg-4 col-md-4 col-sm-4 ${extraClass}`}>
            <div className="picture-container" style={{marginLeft: 18}}>
                <div className={`picture ${borderClass}`}>
                    <FontAwesome name={pictureIcon} size="3x" className="picture-src"/>
                </div>
            </div>

            <div className="uploadButtonBox" style={{width: '100%', textAlign: 'center', marginTop: 20}}>
                <label className={`fileUploadButton ${borderClass}`}>
                    <FontAwesome name={icon} className="faIcon" style={{height: '39px !important'}}/>
                    <span className={`btnFileText ${btnName}`}>{name}</span>
                    <input id="btnFile" type="file" style={{display: 'none'}} onChange={onFileChange} name={name}/>
                </label>
            </div>
            {added_file}
            {removeButton}
            <div className="errorBox">{errors}</div>
        </div>
    );
};

一切正常。只有一种情况不能按预期工作。

如果选择了文件,则显示小remove按钮(来自FileInputButton组件的removeButton)。如果我点击它,主要组件的removeFile函数被调用,我改变状态(找到该状态的文件,将其删除,并添加一个具有该文件初始值的新对象,然后更新国家)。

该文件已删除,一切正常。如果我新添加一个新文件,它也可以按预期工作。问题是,如果我尝试再次添加相同的文件,那么工作。根本没有调用handleFiles函数。

如果我添加第一个文件然后将其删除,则添加新的第二个文件,然后删除第二个文件,然后再添加第一个文件,它可以正常工作。

唯一的问题是,如果我添加第一个文件,然后删除它,然后尝试再次添加它不起作用。我在控制台中没有任何错误。

知道我做错了吗?

1 个答案:

答案 0 :(得分:2)

您的文件输入上有onChange处理程序,但是当您从状态清除文件时,您不会从输入中清除它。因此,当您尝试再次上载同一文件时,不会触发onChange事件,因此不会调用您的处理程序。

将输入文件值设为''以重置它。

假设您的删除处理程序看起来像这样。

handleDelete(){
    document.querySelector('input[type=file]').value = '';
    this.props.removeFile(this.props.fileType, this.props.fileName);
}

这段代码可能并非完全符合您的代码精神,但您会明白这一点。