2

I asked this question yesterday but upon reading it I noticed I worded it poorly, allow me to rephrase. What I'm trying to achieve is have one initial group (an array) and allow a user to create more groups (add arrays). And with each group they can upload images. And for each uploaded image I want to show a preview within it's respected group.

enter image description here

The image above is the initial group (an empty array). You can see this by my current state.

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

I map through groups to display the image above which consists of an input["file"] aswell as a div to the right that display's the photo preview. This code looks as such..

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>
})

Where I'm having trouble is getting the file and image preview into the same index in the respected array (groups and preview). Right now my onChange event handler looks like this.

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)
}

Is what I'm trying to do not possible with the spread operator in this.setState? What I want to achieve would seem to be done more like

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

but something like that is a syntax error. Is there a better way to do this?

SOLUTION**

2
  • I would go for a different data structure and try with a lookup object Commented Sep 20, 2018 at 19:49
  • Ryne is the issue resolved ? i have added my answer did you try that way ? Commented Sep 22, 2018 at 8:10

2 Answers 2

2

You will have to grab the item from the array based on the index, and then add the file to the item that was just grabbed.

index is just a number and you are applying a spread operator against it which is the reason for the error.

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
  })
}
Sign up to request clarification or add additional context in comments.

4 Comments

dont you think this way the arrays are just being shallow-copied
That is the intent as state has to be immutable. It is a bad idea to mutate the state directly.
I console log after the file upload and the groups is empty and the preview is undefined. This code makes sense though I'm going to play around with it as I can't see as of now why the file & reader.result would show up null or undefined
the code in this answer was a little different than my solution but this had gotten me to it. I edited my question with the solution
0

try updating the state this way:

 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 )
    })
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.