在React中添加和删除N个文件输入

时间:2018-06-27 19:58:03

标签: javascript reactjs

我正在构建允许用户上传N个数据文件的工具。为此,我添加了一个按钮,它将创建一个附加的文件上传选项。这是通过渲染函数中的一个简单的for循环完成的(只有在满足某些条件时才会出现选择选项,即'mergeColumnSelection'变量,您可以忽略它,但是我将其包括在内以防万一它以某种方式结束变得有意义)

let renderedEnrichedDataFields = [];
for(let i = 0; i < this.state.enrichedData.length; i++) {
  let mergeColumnSelection = ""
  if(this.state.enrichedData[i] !== null) {
      mergeColumnSelection = <div className="form-item__select form-item">
        <label className="form-label" htmlFor="add-target-owner">Merging Column</label>
        <div className="form-item__container">
          <select onChange={(e) => {this.setEnrichedMergeColumn(e, i)}} defaultValue={this.state.csvColumns[0]}>
            {mainDataColumns}
          </select>
        </div>
      </div>
  }

  renderedEnrichedDataFields.push(
    <div className="form-group">
      <button onClick={() => {this.removeEnrichmentData(i)}} type="button" className="modal-close">
        <Icon name="close" />
      </button>
      <div className="form-item">
      <label className="form-label" htmlFor="add-target-csv">Enrichment Dataset</label>
        <input 
          className="csv-input" 
          type="file" 
          accept="text/csv" 
          onChange={(e) => {this.acceptNewEnrichedDataFile(e, i)}} 
        />
      </div>
      {mergeColumnSelection}

    </div>
  )
}

基本上,每次按下按钮时,都会在状态下将新元素推送到richedData数组中。这将导致应用程序呈现其他文件输入。用户上载文件时,数组中的占位符元素将替换为文件。当用户最终提交表单时,将提交一系列文件。

但是!对于删除这些输入字段的功能,我很难获得一个干净的实现。功能

removeEnrichmentData(index) {
  let enrichmentData = this.state.enrichedData
  let enrichedMergeColumns = this.state.enrichedMergeColumns;

  enrichmentData.splice(index, 1);
  enrichedMergeColumns.splice(index, 1)

  this.setState({enrichedData: enrichmentData, enrichedMergeColumns: enrichedMergeColumns});
}

如您所见,这将获取所选输入的索引,然后从生成for循环的数组中将其拼接起来。从数组中拼接了适当的文件,并且文件输入的数量正确。但是,显示什么文件名存在问题。图片会有所帮助:

Here you can see a sample where someone is preparing to upload three files, health, cluster, and starbucks

  

在这里您可以看到一个示例,其中有人准备上传三个   文件,运行状况,群集和星巴克

Now I select to remove the cluster item (item 2) from the list. It is removed from the file list in state, leaving just health and starbucks. However, the for loop simply runs through twice and drops the last item - meaning that it appears that the health and cluster are the remaining two files, even though in actuality they are health and starbucks

  

现在,我选择从列表中删除群集项目(项目2)。它是   从状态中的文件列表中删除,仅保留运行状况和   星巴克。但是,for循环仅运行两次并掉落   最后一项-表示运行状况和集群   是剩下的两个文件,即使实际上它们是健康的   和星巴克

我考虑过将JSX块本身移入状态,以便我可以专门针对要删除的JSX输入元素-但这种方法取得的成功有限,并且读到不建议将JSX置于状态。 React并没有真正构建可轻松删除特定输入的方法,并且我无法在文件输入中设置默认值,因此我无法轻松地将各个输入与其状态对应的输入关联起来。

感觉应该是这样一个简单的问题,我非常困惑。任何帮助表示赞赏!

3 个答案:

答案 0 :(得分:3)

@MilošRašić是正确的-您的最初问题是您可能正在使用数组索引作为输入键。因此,如果您有10个编号为0 ... 9的输入,并且删除了索引为5的输入,那么您仍将使用键0..8渲染项目,而React认为最后一个已被删除。

根据您对使用UUID的评论,听起来好像您正在render()方法本身中生成唯一ID。 请勿这样做! 从不render()中的密钥生成随机值。当您这样做时,您每次都在告诉React“该项目与我们上次渲染的项目不同,请在此处销毁现有项目,并用新项目替换它。”

相反,当您在状态中添加新条目时,应生成这些唯一ID。 。例如:

class FileInputList extends Component {
    state = { inputs : [] }

    addNewFileInput = () => {
        const inputID = uuid();
        const newInputs = this.state.inputs.concat({id : inputID});
        this.setState({inputs : newInputs});
    }

    render() {
        const {inputs} = this.state;

        const inputList = inputs.map(inputEntry) => {
            return <input type="file" key={inputEntry.id} />
        });

        return inputList;
    }
}

答案 1 :(得分:2)

很难确定没有一个完整的示例,但这非常类似于一个“有效”的示例,该示例在您不给元素数组提供关键道具时,React如何混乱。你没有从React那里得到警告吗?尝试为要推送到数组的div提供一个关键道具,该道具在删除元素时不会更改现有元素(因此key = {i}无效)。

例如,如果您正在渲染

<input type="file" key={1} />
<input type="file" key={2} />
<input type="file" key={3} />
<input type="file" key={4} />

当您删除带有key = {2}的钥匙时,应该是

<input type="file" key={1} />
<input type="file" key={3} />
<input type="file" key={4} />

诸如关系数据库中的某种递增ID或生成的唯一ID可以解决问题。

答案 2 :(得分:1)

您尝试过吗:

{this.removeEnrichmentData(index)}}

这里是工作中的example