Reputation: 35
I'm trying to figure out what I'm not doing well.
I have a shops object which is a database with different shop inside. I want to render each shop's information in their own page thanks to react-router.
I already try many way to render my details.
The error that always come back its that I can read props, or state of undefined in my shopDetails component. When I want to console log my location element, it is shown as undefined but when I go to my react developer tool I can see my shops data right stored in my shopDetails props.location...
I really don't understand how to render the good data. I open all other subject without understanding how to deal with my problem.
If you could help on this, it would be amazing. Thanks for your time.
App.js
render() {
return (
<Router>
<HeaderFilters
wrapperHeaderFunction={this.wrapperHeaderFunction}
zip_code={this.state.zip_code}
handleChanges={this.handleChanges}
isClicked={this.isClicked}
filterClick={this.filterClick}
selectedOption={this.state.selectedOption}
moreFilterClick={this.moreFilterClick}
filteredResults={this.state.filteredResults}
rating={this.state.rating}
startDate={this.state.startDate} // momentPropTypes.momentObj or null,
startDateId="your_unique_start_date_id" // PropTypes.string.isRequired,
endDate={this.state.endDate} // momentPropTypes.momentObj or null,
endDateId="your_unique_end_date_id" // PropTypes.string.isRequired,
onDatesChange={({ startDate, endDate }) =>
this.setState({ startDate, endDate })
} // PropTypes.func.isRequired,
focusedInput={this.state.focusedInput} // PropTypes.oneOf([START_DATE, END_DATE]) or null,
onFocusChange={focusedInput => this.setState({ focusedInput })} // PropTypes.func.isRequired,
/>
{this.state.isMoreFiltersRequired ? (
<MoreFilters
handleChanges={this.handleChanges}
isClicked={this.isClicked}
filterClick={this.filterClick}
moreFilterClick={this.moreFilterClick}
filteredResults={this.state.filteredResults}
rating={this.state.rating}
/>
) : null}
<div>
{this.state.login ? <Spinner animation="border" size="xl" /> : null}
</div>
<Switch>
<Route
exact
path="/"
render={() => (
<ShopPreview
loading={this.state.loading}
shops={this.state.shops}
filteredResults={this.state.filteredResults}
rating={this.state.rating}
/>
)}
/>
<Route
path="/search"
render={() => (
<ShopSearch
loading={this.state.loading}
shops={this.state.shops}
filteredResults={this.state.filteredResults}
rating={this.state.rating}
/>
)}
/>
<Route
path={`/shopDetail/:id`}
render={routeProps => (
<ShopDetails {...routeProps} shops={this.state.shops} />
)}
/>
</Switch>
</Router>
);
}
}
export default App;
Shops.js (the component which renders the shop list)
render() {
return (
<Container>
<ListGroup>
{this.props.shops.map((detail, index) => (
<ListGroup.Item key="index">
<Row>
<Col>
<Image
alt=""
src={detail.imgURL}
width={150}
height={150}
rounded
/>
</Col>
<Col>
<h3 className="shop_title">{detail.nom}</h3>
<StarRatings
rating={this.props.rating}
starRatedColor="#DAA520"
changeRating={this.changeRating}
numberOfStars={5}
starDimension="15px"
name="rating"
starSpacing="2px"
/>
<p id="resume">{detail.resume}</p>
</Col>
<Col>
<Row>
{detail.startPrice === ""
? "Sur devis"
: "A partir de " + detail.startPrice + " €"}
</Row>
<Row>
{/* Make route with id, with key= detail.id */}
<Link
to={{
pathname: "/shopDetail/" + detail.id,
state: {shops : this.props.shops}
}}
>
<Button
className="detailButton"
key={detail.id}
variant="primary"
onClick={this.props.filterClick}
>
Détails
</Button>
</Link>
</Row>
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
</Container>
);
}
}
export default Shops;
ShopDetails.js (the component which renders the shop details according to its URL id)
import React, { Component } from 'react'
class ShopDetails extends Component {
constructor(props){
super(props)
this.setState({
})
}
render() {
console.log("Props shops: " ,this.props.shops)
const id = window.location.pathname.replace("/shopDetail/", "");
const data = this.props.shops
const location = this.props.location
console.log("Location:", location)
const shop = data.find(s => s.id === id)
return (
<div>
<h1>{shop.id}</h1>
<h3>{shop.nom}</h3>
<p>{shop.website}</p>
</div>
)
}}
export default ShopDetails
For now, I'm just allow to render the id, but I can't access to my elements "shops" in my state which stock my shop data to map on each component.
edit: SCREENSHOT CONSOLE.LOG
edit2:
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)
return (
<div>
</div>
)
}}
export default ShopDetails
Edit3
Screen log object developed1 Edit3
Screen log object developed2 Edit3
Edit 4:
const shop, can finally be render something in console.log
Problem was about a triple = in my const shop = data.find(s => s.id == id)
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
Now I have to return my data stored in my shop const, see below the link of the console.log(shop) since the edit 4
Upvotes: 1
Views: 693
Reputation: 35
Finally, solve my problem !
So first I had this problem with my === operator as well explain Domino987 previously.
Then if I couldn't render my {shop.nom} element even if I could see my shop element in my props.
click to see my console.log("const shop = data.find(...): ", shop);
It is because at the moment the component renders, there is not value inside shop. We can know that by looking at the 'i' icon in my dev tools.
So I had 2 options:
You have 2 options:
Put all my 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.
Conditional render. Example:
if (!shop.nom){
return null
} else {
return <h1>{shop.nom}<h1/>
}
OR :
{Boolean(shop.nom) ? <h1>{shop.nom}<h1/> : null}
I used ternary method with the following code:
class ShopDetails extends Component {
constructor(props) {
super(props);
this.state = { }
}
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 className="container">
<Row>
<Col>
{shop ? (
<Image
alt=""
src={shop.imgURL}
width={150}
height={150}
rounded
/>
) : null}
</Col>
<Col >
{shop ? <h1>{shop.nom}</h1> : null}
{shop ? <h2>A partir de {shop.startPrice} €</h2> : null}
</Col>
</Row>
<Row >
<Col >
<h3>Site internet:</h3>
{shop ? <p>{shop.website}</p> : null}
</Col>
<Col >
<h3>Services</h3>
<p>Rappel des services</p>
</Col>
</Row>
<Row >
<Col>
<h4>Présentation</h4>
{shop ? <p>{shop.resume}</p> : null}
</Col>
</Row>
</div>
);
}
}
export default ShopDetails;
That solve my problem, and I could finally render my elements.
If that could help someone, I will be glad !
Thanks to all the community for helping me in my project !
Upvotes: 0
Reputation: 8804
You have to set the == instead of === because the id of your shop is a number and the id from your url is a string. If you cast the id from your url to number, it should also work with ===. To render your shop data, after you find it, should not be done with map since you cannot access the object keys with it. You should just render it with shop.nom etc. Hope this helps. Happy coding.
Upvotes: 0