更新this.setState中的嵌套数组

时间:2018-09-20 18:51:45

标签: reactjs

昨天我问了这个问题,但是在阅读时我注意到我的措辞很差,请允许我重新表述。我要实现的目标是拥有一个初始组(一个数组),并允许用户创建更多组(添加数组)。每个小组都可以上传图像。对于每个上传的图像,我都希望在其受尊敬的组中显示预览。

enter image description here

上面的图像是初始组(一个空数组)。您可以通过我当前的状态看到它。

this.state = {
    data: {
        groups: [[]]
    },
    preview: [[]]
}

我通过组进行映射以显示上面的图像,该图像由input [“ file”]以及显示照片预览的右侧的div组成。这段代码看起来就是这样。

groups.map((element, index) => {
    return <div className="form-group" key={index}>
        <label htmlFor={"photos-" + index} className="form-group-label">Upload Photo</label>
        <input
            id={"photos-" + index}
            type="file"
            style={{display: 'none'}}
            onChange={(e, index) => this.handlePhotoChange(e, index)}
        />
        <div className="form-group-previews">
            {
                preview[index].map((image, id) => {
                    return <img key={id} src={image} alt={id} />
                })
            }
        </div>
    </div>
})

我遇到麻烦的地方是将文件和图像预览放入受尊重的数组(组和预览)中的同一索引中。现在,我的onChange事件处理程序看起来像这样。

handlePhotoChange(e, index) {
    e.preventDefault()

    let reader = new FileReader()
    let file = e.target.files[0]

    const { data, preview } = this.state
    const { groups } = data

    reader.onloadend = () => {
        this.setState({
            data: {
                ...data,
                groups: [...groups, [...index, file]] // error
            },
            preview: [...preview, [...index, reader.result]] // error
        })
    }

    reader.readAsDataURL(file)
}

在this.setState中,使用传播运算符是我无法做到的吗?我想要实现的目标似乎更像是

groups[index]: [...groups[index], file]
preview[index]: [...preview[index], reader.result]

但是类似的东西是语法错误。有更好的方法吗?

解决方案**

2 个答案:

答案 0 :(得分:2)

您将不得不根据索引从数组中获取项目,然后将file添加到刚刚获取的项目中。

index只是一个数字,您正在对它应用扩展运算符,这就是错误的原因。

reader.onloadend = () => {
  // clone the array from state so that it is not mutated directly
  let clonedGroups = [...groups];
  let clonedPreview = [...preview];
  // grab the corresponding item based on the index
  let groupItem = clonedGroups[index] || [];
  let previewItem = clonedPreview[index] || [];

  // Update the corresponding item
  groupItem = [...groupItem, file];
  previewItem = [...previewItem, reader.result];

  // set the state with updated array objects
  this.setState({
    data: {
      ...data,
      groups: clonedGroups
    },
    preview: clonedPreview
  })
}

答案 1 :(得分:0)

尝试以这种方式更新状态:

 reader.onloadend = () => {
    this.setState({
        data: {
            ...data,
            groups: groups.map((groupItem, i)=> i===index?[...groupItem,...file] : groupItem )
        },
        preview:  preview.map((previewItem, i)=> i===index?[...previewItem,...reader.result] : previewItem )
    })
}