Search code examples
arraysreactjsreturncomponentsmap-function

React- Map function in component doesn't work


I'm working with a small application, where I am using react.js. Since I am a beginner I have some issues with it.

I want to map my array, but it won't work. I followed a youtube tutorial and the difference is that the array is populated with hardcoded data. I'm fetching my data and add it into the array when the fetch is complete. (JSON objects).

import React from "react";
import Product from "./Product"

export default class ProductList extends React.Component{
render()
{ console.log("productlist")

    return (
     <ul>
     {this.props.products.map((product, i) => 
        { return <Product product={product} key={i}/>  })}
        {console.log("test")}
    </ul> 
     )

}
}

The console.logs works, but the map-function does not. I have tried without the Id, and in different ways but it won't work. I want the data to pass into my last component, called Product. There are my < li> elements I want to get populated.

When I just passed the "this.props.products" in to "" then I reached the Product component, but no population of data. import React from "react";

export default class Product extends React.Component{
render(){
    console.log("product")

    return (   
  <li> {this.props.product.title} {this.props.product.price} <img src={this.props.product.imageUrl}/> </li>
    )
}
}

I'm using a fetch method to get data from a Json-file.

fetch('http://localhost:8080/products')
.then(
response =>
  response.ok
    ? response.json()
    : Promise.reject(Can't communicate with REST API server (${response.statusText})`),
)
.then(products => {
    products.forEach(product => productArray.push(product));
})

As you can see above I'm adding the products from the Jsonfile into an array I've created. And I am not sure if that is the thing that causes my problem.

import React from "react";
import ReactDOM from "react-dom";
import Container from "./Components/Container";

let productArray = []; 
const app = document.getElementById('app');
ReactDOM.render(<Container products={productArray}/>, app)

I am passing my array into my Container.js file using the ReactDOM.render. And inside of the Container.js file, I also have import React from react and import ProductList from ./Productlist. So I continue to pass the array (and I have checked if there are values in it, and there is.

  <ProductList products = {this.props.products}/>

Solution

  • It happens because products is outdated by the time your fetch request finishes. And even though you are updating it (by productArray.push) your component doesn't know about such change. Not to mention that this is a bad pattern.

    For that, use proper React component lifecycle methods and state handling.

    In your Container component:

    const Container extends React.Component {
      constructor(props) {
        super(props)
    
        this.state = {
          products: [], // Initialize product as an empty array
        }
      }
    
      componentDidMount() {
        fetch('http://localhost:8080/products')
          .then(response =>
            response.ok
              ? response.json()
              : Promise.reject(`Can't communicate with REST API server (${response.statusText})`),
          )
          .then(products => {
            this.setState({ products }) // Notify your component that products have been fetched
          })
      }
    
      render() {
        return (
          <div>
             ...
            <ProductList products={this.state.products} />
          </div>
        )
      }
    }
    

    Please not that setState may be asynchronous. Should you fetch new data in the future, don't hesitate to use such feature as well pointed by @Luke M Willis:

    this.setState(prevState => ({
      products: [ ...prevState.products, ...products ],
    }))