1

I am trying to map over one of the two arrays from my imported js file ProductInformation.js.

This is in my main component class <ProductSquare arrayId = {door}/> I have also tried <ProductSquare arrayId = {['door']}/>

What I am trying to do is only map the array (out of the two) which matches the panelId prop variable.

I get an error of TypeError: Cannot read property 'map' of undefined

export const door = [
  {
    id: 1,
    productSquareId: 'door',
    productImage: require('./door.png'),
    companyImage: require('./logo.png'),
    price: '$55.99',

  },
  {
    id: 2,
    productSquareId: 'door',
    productImage: require('./door.png'),
    companyImage: require('./logo.png'),
    price: '$55.99',

  },
  ]
  
  export const lighting = [
  {
    id: 1,
    productSquareId: 'lighting',
    productImage: require('./lighting.png'),
    companyImage: require('./logo.png'),
    price: '$55.99',

  }

import React, { Component } from 'react';
import './ProductSquare.css';
import './grid-container.css'
import  {door, lighting} from './ProductInformation.js';


class ProductSquare extends Component {

constructor(props)
{
  super(props)
    this.state = {
    };
}

PopulateProductSquares()
{

  const ProductSquares = this.props.arrayId.map((product, i) =>
    <div className = "ProductSquare">
    <img  className = "MainImage" src ={this.props.arrayId[i].productImage}  alt = "test"/>
    <img  className = "CompanyImage" src ={this.props.arrayId[i].companyImage} alt = "test"/>

      <button className = "AddButton">
        Add 
      </button>

      <button className = "InfoButton">
        Info
      </button>

    </div>
  )

  return (
     ProductSquares
  )
}


  render() {
    return (
      this.PopulateProductSquares()
    )

}
}

export default ProductSquare;

2
  • Can you post an MCVE to somewhere like stackblitz.com ? Commented Jun 20, 2018 at 23:54
  • I think you might be losing the this reference. Have you tried moving the whole PopulateProductSquares function to the render? I think it's unnecessary to have it outside. Commented Jun 21, 2018 at 0:08

2 Answers 2

1

As Alan pointed out, I think the main problem is that when you are referring to this, it is not bound to the main component. For functions that are not part of the standard React component lifecycle (constructor, render, componentDidMount, etc), you must explicitly state that you bind it to the component like this

constructor(props)
{
  super(props)
    this.state = {};

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

That by itself should resolve the immediate problem you are facing.

In addition, I would point out a few things that would make your component a little bit easier to read. For example, having the internal function PopulateProductSquares start with a capital letter, makes us think that it is a Class or Component, so I would rename that populateProductSquares (or renderProductSquares in my personal opinion to indicate what it does).

Secondly, when you are looping through the products, you don't need to refer to this.props.arrayId[i] since each object is already passed as the product argument in the function (product, i) => when you use map.

And you don't need to assign the result from this.props.arrayId.map(...) to an constant since you are returning it right away.

Lastly, since the only thing you are doing in the render method is to call the PopulateProductSquares function, it doesn't make sense to separate it into a separate function, you could just write it all directly in render (as Alan also pointed out). But there are a lot of useful cases where you do want to have it in a separate function, so I think it is important to understand the requirement for binding functions.

To summarise, here is how I might have done it (with a slightly different render function to showcase when you might want to have separate functions).

class ProductSquare extends Component {

  constructor(props)
  {
    super(props)
    this.state = {};

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

  renderProductSquares()
  {
    return this.props.arrayId.map((product, i) =>
      <div className = "ProductSquare" key={i}>
        <img  className = "MainImage" src ={product.productImage}  alt = "test"/>
        <img  className = "CompanyImage" src ={product.companyImage} alt = "test"/>

        <button className = "AddButton">
          Add 
        </button>

        <button className = "InfoButton">
          Info
        </button>
      </div>
    );
  }

  render() {
    return (
      <div>
        <h1>Here are a bunch of product squares</h1>
        {this.renderProductSquares()}
      </div>
    );
  }
}

export default ProductSquare;
Sign up to request clarification or add additional context in comments.

1 Comment

Thank You for your helpful solution. I found out that the problem <ProductSquare arrayId = {door}/> What I did was import my .js file into my component class instead of my parent class. Now {door} is defined because I imported my .js data file. My logic was that I go into my component class with a prop keyword of the array name and access the appropriate array. The correct logic is that I go into my component class with a prop that is the whole array and than I can call it.
0

I'll take a swing at what you are trying to do here:

<ProductSquare arrayId="door" />

In order to get to the door array of your ProductInformation.js file, it would probably be better to have a default export:

/* ProductInformation.js */
export default {
  door: [/* ...door info*/]
  window: [/* ...window info */],
};

Then when you import it, you would:

import products from "./ProductInformation.js";

For your map function, you would want to use your products import with your props.arrayId:

const ProductSquares = products[this.props.arrayId].map(...);

In your current code, you are trying to map over the string prop you are passing to your component. What you want is to index the correct product array. You need to either create the default export (written above), or create a map in your render function:

const productMap = { door: door, window: window };
const ProductSquares = productMap[this.props.arrayId].map(...);

2 Comments

I understand almost all of what you said except the last part. I thought when I have no quotations I pass it as a variable? <ProductSquare arrayId = {door}/> Do I need to pass it as a string? I did a default export on ProductInformation.js but here const productMap = { door: door, window: window }; , i get an error of Line 18: 'door' is not defined no-undef Line 18: 'lighting' is not defined no-undef
Thank You for your helpful solution. I found out that the problem <ProductSquare arrayId = {door}/> What I did was import my .js file into my component class instead of my parent class. Now {door} is defined because I imported my .js data file. My logic was that I go into my component class with a prop keyword of the array name and access the appropriate array. The correct logic is that I go into my component class with a prop that is the whole array and than I can call it.

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.