Why this state returns null in react?

Hello,

This is related to an upload image code.
Here come states:

this.state = {
            redirect: null,
            selectedFile: null,
            description: null,
            uploadResult: null,
            selectedFileName:null,
            fileIdList: []

        };

once the input changed:

<input type="file" onChange={this.onFileChange} />

This method is run:

onFileChange = event => {
        this.setState({ selectedFile: event.target.files[0] });
        this.setState({ selectedFileName: event.target.files[0].name });
    };

but when I provide it for a context:

<ImageContext.Provider value={this.state.selectedFileName.data}>
</ImageContext.Provider >

I encounter a null object on the consumer part!

WHY?
while it should contain the name of the clicked object!

Thanks

It’s difficult to help without a working example somewhere on Codepen or Codesandbox, and you haven’t included all relevant parts of the code. Have you tried anything to debug?

  • does the event fire?
  • if it fires, are the values for event.target.files[0] and event.target.files[0].name what they should be?
  • it’s been a while since I used context, onFileChange is the function that updates the Provider state? Does it update correctly?

You can see the code below:


import React, { Component } from 'react';
import { Redirect } from "react-router-dom";
import ImageContext from '../ImageContext';


//import React, { useState } from 'react';


export default class ImageUpload extends Component {
    static displayName = ImageUpload.name;

    constructor(props) {
        super(props);
        this.state = {
            redirect: null,
            selectedFile: null,
            description: null,
            uploadResult: null,
            selectedFileName:null,
            fileIdList: []

        };

        this.onNavToEditor = this.onNavToEditor.bind(this);
    }

    getList = () => {
        fetch('api/Image')
            .then(response => response.json())
            .then(data => this.setState({ fileIdList: data }));
    };

    componentDidMount() {
        this.getList();
    };

    onFileChange = event => {
        this.setState({ selectedFile: event.target.files[0] });
        this.setState({ selectedFileName: event.target.files[0].name });
    };

    
    onDescriptionChange = event => {
        this.setState({ description: event.target.value })
    };
    onFileUpload = async () => {

        const formData = new FormData();

        formData.append(
            "ImageData.File",
            this.state.selectedFile,
            this.state.selectedFile.name
        );



        fetch('/api/Image', {
            method: 'POST',
            body: formData
        }).then(resposne => resposne.json())
            .then(data => {
                console.log(data);
                this.setState({ uploadResult: "File " + data.fileName + " successfully uploaded." });
                this.getList();
            });
        
    };


    onNavToEditor = async () => {

        //this.onFileChangeName();
       
        this.setState({ redirect: "/ImageEditor" });
        //this.setState({ selectedFileName: });



    };

    

    listItems = () => {
        const listItems = this.state.fileIdList.map((item) =>
            <div key={item.imageId.toString()}>
                <img src={"/api/Image/DownloadImage/" + item.imageId}
                    alt={item.fileName}
                    className="img-thumbnail"
                    height="100" width="100" />
            </div>
        );
        return (<div>{listItems}</div>);
    };

    render() {
        if (this.state.redirect) {
            return <Redirect to={this.state.redirect} />
        };
        const mystyle = {

            backgroundColor: "DodgerBlue",
            margin: "100px",

            height: "100px",
            width: "100px"


        };

        return (
            <ImageContext.Provider value={this.state.selectedFileName.data}>
            <div>
                <div style={mystyle} onClick={this.onNavToEditor} />
                <h1>File Upload Demo</h1>
                <div >{this.state.uploadResult} onClick={this.onNavToEditor}</div>
                <div>
                    <input type="file" onChange={this.onFileChange} />
                    <input type="text" value={this.state.value} onChange={this.onDescriptionChange} />
                    <button onClick={this.onFileUpload}>
                        Upload!
                    </button>

                </div>

                    <div onClick={this.onNavToEditor}>

                    {this.listItems()}

                 </div>

            </div>

            </ImageContext.Provider >

        );

    }
}







How am I supposed to debug that, from carefully reading every single line (twice)? You have a lot of async stuff involved, I have no idea what’s happening with your code at any given time.

I hope you’re lucky and someone with a better eye and more time will check if something doesn’t look right. Meanwhile, have you made any attempts to debug this yourself?

Everything works just fine. The problem is the one I told you about earlier in the first post.

The provider return null.

Your Provider’s value is this.state.selectedFileName.data. Have you tried logging that?

No really. I still don’t know how to log in react.
If you know please inform me. :neutral_face:

You log just like in regular JavaScript:

console.log(myVariable).

The thing about React is that you have to get a feeling for where and when you log. In a component that receives stuff from a parent component, I always log right before the render method. At that point, I can be fairly certain that I get a fresh, updated value. That’s where you’d log the values that your Context.Consumer receives.

Your Provider sets this state: selectedFileName: event.target.files[0].name. In that case, you want to know what the value is when this.setState happens, so you would log that inside the onFileChange handler, right before you actually set state.

You’ll find that event.target.files[0].name is a String, containing the file name.

The value of your Provider is this.state.selectedFileName.data. But there’s no .data property on a String, so the value is undefined.

I can’t help you further without a working demo. You’ll have to learn how to debug your own code.

Thanks a lot for your help. I will do this and return the result tomorrow. But I have tested the this.state.selectedFileName at the beginning and the result was the same: null

This is the chrome dev tools expectation.

this.state.selectedFilename is a string, look, you are setting it as a string:

this.setState({ selectedFileName: event.target.files[0].name });

That is a string.

I don’t know how many times I’ve now said this to you, but a context is a way to store an object. The value of the value prop on the provider has to be an object, with one exception. You cannot store anything else there except null. Strings do not have a property data, so the reason it is null is because the value of "mystring".data is null.

It doesn’t matter how many times you write that code where you try to directly store a string instead of an object, React will not magically change how it works.

Thanks for your answer.
What should I restore in the provider?
Thanks