luvs2spuge
luvs2spuge

Reputation: 75

Why won't URL be placed in the state array?

I'm trying to place the image's URL uploaded by the user into an array followed by displaying that image in the view. With my code, all I get is an empty [] in the console. Why won't any image URLs go in the array and then display that image in my view?

JS state and function

this.state = {
            selectedFile: null,
            previewImgURL: '',
            pictures: []
        };
        this.imageUpload = this.imageUpload.bind(this);
}

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

        reader.onloadend = () => {
            this.setState({
                selectedFile: file,
                previewImgURL: reader.result,
                pictures: [...this.state.previewImgURL, this.state.previewImgURL]
            });
        };

        if (file) reader.readAsDataURL(file); // Allows user to preview image uploaded

        this.setState(() => ({file}));
        console.log(this.state.pictures); // in console, all I get's an empty []
    }

JSX code:

    <div className="inputWrapper">
                    <input
                        id="new_post_image"
                        name="post_image"
                        className="button is-success is-outlined"
                        type="file"
                        style={{display: 'none'}}
                        onChange={this.imageUpload}
                        accept="image/*"
                    />
                    <label className="button is-success is-outlined" htmlFor="new_post_image">Upload</label>
                </div>

                {
                    this.state.pictures.map(key => (
                        <div className="uploaded-pics">
                            <Feed src={this.state.previewImgURL[key]} key={key} />
                        </div>
                    ))
                }
</div>

Here is Feed.js:

import React from 'react';
import './Feed.scss';

const feed = (props) => {
    return (
        <div className="row">
            <div className="col-md-6 col-sm-6">
                <img src={props.src}/>

            </div>
        </div>
    );
};

export default feed;

Upvotes: 0

Views: 58

Answers (2)

Brandon  Baars
Brandon Baars

Reputation: 26

I think the issue lies within the line where you're actually adding the pictures to the state. this.setState({ selectedFile: file, previewImgURL: reader.result, ----> pictures: [...this.state.previewImgURL, this.state.previewImgURL] });

When you're using the spread operator, you don't actually have this.state yet so the this.state.previewImgURL doesn't exist yet.

I would just try:

this.setState({
  selectedFile: file,
  previewImgURL: reader.result,
  pictures: [reader.result]
});

I'm also not sure of the usage of the ... (spread) syntax within that context. If you wanted to just update the pictures part of the state (given you already have state) you can use it as:

this.setState({
  ...this.state,
  pictures: [reader.result]
});

Another thing worth noting is you're updating the state within a callback so it won't be guaranteed to be populated when you call your console.log(this.state.pictures)

Also, you're within the same cycle so your state hasn't been updated.

For extra debugging, put some sort of debugger somewhere in the Chrome DevTools and in the console type this.state.picture. This will display the pictures part of the state and in the debugger you will also be able to step over your program. Go here for more info on DevTools debugging: https://developers.google.com/web/tools/chrome-devtools/javascript/

Upvotes: 1

Liren Yeo
Liren Yeo

Reputation: 3451

Have quick read up on React Documentation of setState.

If you console.log(this.state) right after a setState, you're still inside the old cycle, where the states are still the old value.

After the state change, render gets triggered, and if you log this.state there, you will be able to see your updated states.

Another way of immediately accessing an updated state is by using a callback as 2nd argument of setState:

        reader.onloadend = () => {
            this.setState({
                selectedFile: file,
                previewImgURL: reader.result,
                pictures: [...this.state.previewImgURL, this.state.previewImgURL]
            }, () => {
                console.log(this.state.pictures) // this should show you the latest state
            });
        };

Upvotes: 0

Related Questions