How to map data according to button id

The path you are trying to get into is wrong. If you look carefully there is not this.state.location.shops;
plus, that path also looks weird to me.

I can see that you have shops in your this.props.shop in the screenshot you sent, I supposed there is the data you want

Here are all my console.log

Yeah the data I want is my shops object according to the id in the path.

import React, { Component } from 'react'

class ShopDetails extends Component {
    constructor(props){
      super(props)
      this.setState({
        shop:{}
      })
    }
  render() { 
     
      console.log("Props shops: " ,this.props.shops)
      const id = window.location.pathname.replace("/shopDetail/", "");
      console.log("id: ", id)
      const data = this.props.shops
      console.log("data: ", data)
      const location = this.props.location.state
      console.log("Location:", location)
      const shop = data.find(s => s.id === id)
      console.log('shop: ', shop)
      return (
  <div>
  
  </div>
)    
}}
 
export default ShopDetails

Why are you trying to get into this.props.location.state? Forget that, the information you need is in this.props.shops, no? Also, im pretty sure this.props.location is a property of react-router; and it works for getting the pathname, and you already have it in the id variable.

If you see that shop is undefined; but there is information in you variable data (where you are getting the information from); then the problem is your filtering. Check it is filtering correctly.

Ok, here its yet better:

import React, { Component } from 'react'

class ShopDetails extends Component {
    constructor(props){
      super(props)
      this.setState({
        shop:{}
      })
    }
  render() { 
     
      console.log("Props shops: " ,this.props.shops)
      const id = window.location.pathname.replace("/shopDetail/", "");
      console.log("id: ", id)
      const data = this.props.shops
      console.log("data: ", data)
      const shop = data.find(s => s.id == id)
      console.log("shop: ", shop)
      console.log("this.props.match.params.id: ", this.props.match.params.id)
      
      return (
  <div>
    
  
  </div>
)    
}}
 
export default ShopDetails

I had a “===” on my const shop, that’s why I had this undefined.

Now I can have this in my console.log(shop):

C

Now I had to find how to render this in my return, and I think my problem will be all fix !

In that case it would be under:

this.props.location.state.shops

since this.props.location.shops is not a valid property on the object.


I wouldn’t recommend storing state in window.location, which is what you’ve done here. Instead, just access shops directly from this.state or this.props.

This is because this.props.location is a reference to window.location, so you’re actually mutating the global location property.

Edit:
I see you’ve already accessed your data from this.props. I’d still recommend you also grab the location from this.props rather than window.location.pathname.replace("/shopDetail/", "")

1 Like

Yeah, I update this with my answer bellow. Now have to find the way to return what I need :thinking:

edit: Ok I will update this too, grab location from this.props

You can access everything inside the render() closure. If you want to use javascript inside jsx components, make sure to use curly braces like this:

<div>{some.map(javascript)</div>}

Ok, here we go. I try this, but I missed something:

import React, { Component } from 'react'

class ShopDetails extends Component {
    constructor(props){
      super(props)
      this.setState({
        shop:{}
      })
    }
  render() { 
     
      console.log("Props shops: " ,this.props.shops)
      const id = window.location.pathname.replace("/shopDetail/", "");
      console.log("id: ", id)
      const data = this.props.shops
      console.log("data: ", data)
      const shop = data.find(s => s.id == id)
      console.log("shop: ", shop)
      console.log("this.props.match.params.id: ", this.props.match.params.id)
      
      return (
  <div>
     {shop.map((detail, index) => (
       <div key={index}>
         <h1>{detail.nom}</h1>
       </div>

     ))}
    <p>{data.id}</p>
  
  </div>
)    
}}
 
export default ShopDetails

Like this so ?

The error says ‘Cannot read property map of undefined’. Look at the error trace, and find the highlighted line. It will have a ‘^’ where the error starts. Then look to see why there is no map method on that object.

Take a look at this to see what it returns

To render my shop data, should not be done with map since I cannot access the object keys with it. I should just render it with shop.nom etc.

But when I try to render it with {shop.nom}, I have an error return saying TypeError: Cannot read property ‘nom’ of undefined What is weird because I have an object with this “nom” key inside as you can see in my last screen shot edit

But when I try to render it with {shop.nom}, I have an error return saying TypeError: Cannot read property ‘nom’ of undefined

Are you sure it’s definitely returning something? array.find returns undefined if it does not find a match. In javascript, you have to make sure that each level in an object exists if you want to get it. That means if you have

const obj = {
  a: {
     b: {
       c: 10
     }
   }
}

and you want to get the value at c, you have to do

// ternary
const valueOfC = a && a.b && a.b.c || 'not found'

// regular
let valueOfC = 'not found'

if(a && a.b && a.b.c) valueOfC = a.b.c

What does console.log show?

Hmm yes, I’m pretty sure, look at my console.log(shop)

It contents my shop object, matching with my id, ready to be display :slight_smile:
(if only I knew how ^^)

That is weird. The only things I can think of doing right now are these steps:

  1. refresh the browser
  2. close and reopen the browser
  3. try a different browser
  4. return JSON.stringify(shop, null, 2) -> this should print out the whole object

try these and get back to me with your findings. We’re probably overlooking something

My point is may be an error from component life cycle :confused: . But yes, I will try to verify what you are saying too.
I’ll let you know quickly. Thanks anyway for your time !

you might be right on this one.

Thanks anyway for your time !

Your welcome!

Try:

render() { 
     
      console.log("Props shops: " ,this.props.shops)
      const id = this.props.match.params.id;
      console.log("id: ", id)
      const data = this.props.shops || {}
      console.log("data: ", data)
      const shop = data.find(s => s.id == id)
      console.log("const shop = data.find(...): ", shop)
      
      return (
  <div>
     {shop.map(home => <div>{home.nom}</div>)}
   
  </div>
)    
}}

and

class ShopDetails extends Component {
    constructor(props){
      super(props)
      this.setState({
        shop:[]
      }
      )
      
    }
  render() { 
     
      console.log("Props shops: " ,this.props.shops)
      const id = this.props.match.params.id;
      console.log("id: ", id)
      const data = this.props.shops || {}
      console.log("data: ", data)
      const shop = data.find(s => s.id == id)
      console.log("const shop = data.find(...): ", shop)
      
      return (
  <div>
    {
      shop
    }
  </div>
)    
}}
 
export default ShopDetails

This las t try render the following error. Which confirm my object is well fill with my shop data.

Still not working

Let’s test if it’s the lifecycle that’s messed up. Do this in your jsx

{
  if (shop) <div>{shop.nom}</div>
  else null
} 

// or if you like ternary
{
 shop ? <div>{shop.nom}</div> : null
}
1 Like

It is because at the moment the component renders, there is not value inside shop.

You can know that by looking at that icon.

image

You have 2 options:

  1. Put all your information in state, not like shop={}, but like bornePhoto, cabinePhoto, helio, booth… etc, then it first renders with empty information, and then when the information arrives, it updates the state and it will shown.

  2. Conditional render. Example:

if (!shop.nom){
    return null
} else {
    return <h1>{shop.nom}<h1/>
}

OR YOU CAN DO:

{Boolean(shop.nom) ? <h1>{shop.nom}<h1/> : null}
1 Like

Here we go, Thanks a lot to both of you.
Here its render the right shop, with the right information.

So, a last question, that wanna say these kind of error are caused by my way to code? it could be fix with a better life cycle handling ? Or its just normal to have to do this way to render this kind of stuff ?

Once again, Thanks u very much for your time, I really appreciated it.

1 Like

The best practice it to store your data in state, and render depending on the value of that. You will still need to handle if the data is missing. In fact, you should always handle a missing data case.

So in componentDidMount you would call out to the database, while the component renders your default state.

Then when the data comes in, update your state and the component will re-render itself. And the best practice is to render null as a component, which won’t add any nodes to your dom.

So this particular error wasn’t about how you were writing the logic (except for not handling the missing data case).

Happy coding!

1 Like