1

I am new to React and as I was creating a project, I came across a rather peculiar event with my code. It is with the async nature of the setState which doesn't let me render data on my page like i want it to. I am trying to display files which i have in my database already, onto my webpage. But since the state is set after a while therefore i am not able to render my files onto the screen using the map function, since when it is called it is undefined.

I implplemented a get method in so as to get the json response of the files that i want to display. But as I mount my component and setstate of the Files, it shows that it doesn't have any value in it.I know it is async but i have no idea how to handle it so that i can use map to display onto the webpage.

My code is as follows:

import React, {Component} from "react";
// import axios from 'axios'; 
import {Link} from 'react-router-dom';
import {Styles} from '../Styling/Styles';
  

class FileView extends Component {

    state = {
        fileViewData : {}
    }

    // viewFunction(){
    componentDidMount(){

          fetch('http://127.0.0.1:8000/api/uploads/', {
                method: 'GET'
            })
            .then((response) => {
                let data = response.json();
                return data;
            })
            .then((data) => {
                this.setState({fileViewData: data}, ()=>{
                    console.log("hi");
                });
            }).catch(error => {console.log(error)})
            

            // console.log(fileViewData);
            
    }

    render(){
   
        return (

            <React.Fragment>
                <Styles>
                <div className = "appbar">
            
                <Link to='/dashboard'>
                    <button className="homeBtn" label="Back" >
                    Back
                    </button>
                </Link>

                </div>

                {/* <button  label="View" onClick={this.viewFunction} >
                    View
                </button> */}
        
            </Styles>

            //.....section not working since map is not a function of undef......//
            {   

               this.state.fileViewData.map(item =>{
                    return (
                        <h2>{item.fields.file}</h2>
                            );
                            
                 })

            }

            //.......section not working ends.........//
            
            {console.log(this.state.fileViewData)}

        </React.Fragment>
        );
    }
    
}

export default FileView;

The console output is something like this: enter image description here

The empty object is returned twice and then the data is returned twice.I am not running any kind of loop either. How should I set the value so that i am able to display my files onto the screen? TIA!

otaku_weeb
  • 107
  • 10

3 Answers3

1

Looks like your data is an array, so your initial state should also be an array

state = {
  fileViewData: [],
}

Then your check for array length will be correct, but regular javascript doens't quite work the same in JSX. You'll need to conditionally render JSX.

Conditional Rendering

{this.state.fileViewData.length
  ? this.state.fileViewData.map(...)
  : null
}

Since it seems you don't really render anything if there is no data, you can simply map the data as array::map correctly handles empty arrays.

{
  this.state.fileViewData.map(...)
}
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
1
  1. Set state to an empty array
  2. Remove the if condition and anonymous function declaration from your map statement

You declare that function but never invoke it also you don't need it.

if you insist on checking the length

{   
    this.state.fileViewData.length &&
        this.state.fileViewData.map(item =>{
            return (
                <h2>{item.fields.file}</h2>
            );
        })
}
mmason33
  • 878
  • 1
  • 6
  • 10
1

You are getting multiple console logs because when you set state in React you cause the component to render again.

As for your implementation, you probably want the initial value of fileViewData to have the same data structure as what your back end hands back. Currently you start with a plain javascript object, and then turn it into an array of objects once the response comes from your back end.

Without any consideration for a loading period, a simple thing to do to make your application not crash until data loads in would be to make fileViewData an empty array when it is initialized, not an object with no keys. Then it would have the correct prototype to have the method map.

Cory Harper
  • 1,023
  • 6
  • 14