我正在构建允许用户上传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循环的数组中将其拼接起来。从数组中拼接了适当的文件,并且文件输入的数量正确。但是,显示什么文件名存在问题。图片会有所帮助:
在这里您可以看到一个示例,其中有人准备上传三个 文件,运行状况,群集和星巴克
现在,我选择从列表中删除群集项目(项目2)。它是 从状态中的文件列表中删除,仅保留运行状况和 星巴克。但是,for循环仅运行两次并掉落 最后一项-表示运行状况和集群 是剩下的两个文件,即使实际上它们是健康的 和星巴克
我考虑过将JSX块本身移入状态,以便我可以专门针对要删除的JSX输入元素-但这种方法取得的成功有限,并且读到不建议将JSX置于状态。 React并没有真正构建可轻松删除特定输入的方法,并且我无法在文件输入中设置默认值,因此我无法轻松地将各个输入与其状态对应的输入关联起来。
感觉应该是这样一个简单的问题,我非常困惑。任何帮助表示赞赏!
答案 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)