1

I'm trying to display the details of a clickable object on a new page. I've tried a few examples from React Router Pass Param to Component with limited success. The only one that "kind of" worked was Alexander Luna's suggestion to access via ID in component. However, while this returns the id number, I can't access any other values, like "title". I have tried globalStore, however, the error message told me that it isn't defined. I'm not sure that's my best option or not. Ultimately I want the whole object back as I plan to use context with See 'D' below.

App) I have commented out my previous attempts

class App extends Component {
  render() {
    return (
      <React.Fragment>
        <Navbar />
        <Switch>
          <Route exact path="/" component={ProductList} />
          <Route path="/cart" component={Cart} />

          <Route exact path="/details/:id" component={Details} />

          {/* <Route exact path="/details/:id" render={(props) => <Details globalStore={globalStore} 
           {...props} /> } /> */}


          {/* <Route exact path="/details/:id" render={(props)=>{ <Details id={props.match.params.id}/>}} 
           /> */}

          <Route component={Default} />



Details page I want to render in.



import React, { Component } from "react";
export default class Details extends Component {
  render() {
    return(
      <div>
        <h2>{this.props.match.params.id}</h2>
        <h2>{this.props.match.params.title}</h2>
      </div>

The product page, I'm using this link to click through to details.


xport default class Product extends Component {
    render() {
        const { id, title, img, price, inCart } = this.props.product;
        return (
            <ProductWrapper className="col-9 mx-auto col-md-6 col-lg-3 my-3">
                <div className="card">
                    <div className="img-container" onClick={() => console.log('you clicked container')}
                    >
                         <Link to={`/details/${ this.props.product.id }`} >
                            <img src={img} alt="product" className="card-img-top" />
                        </Link>

D - This is how the original code looked, I want to use the {title} tags but I don't know if I need "value => " etc.

      <ProductConsumer>
        {value => {
          const {
            id,
            company,
            img,
            info,
            price,
            title,
            size,
          } = value.Product;

          return (
            <div className="container py-5">
              {/* title */}
              <div className="row">
                <div className="col-10 mx-auto text-center text-slanted text-blue my-5">
                  <h1>{title}</h1>
                </div>
              </div>
John
  • 11
  • 1
  • The only route param you have is `id` (:id) so there is no `params.title`. Where is `title` being passed? – cbr Jan 24 '20 at 22:41
  • You only need id and title or whole object? – Zohaib Ijaz Jan 24 '20 at 22:42
  • I'm trying to access title through an API, which I've already done in the product page. export default class Product extends Component { render() { const { id, title, img, price, inCart } = this.props.product; return ( – John Jan 24 '20 at 22:47
  • Zohaib -- I need the whole object, id and title were just to test, they were the 'furthest', the others attempts just broke the sever. – John Jan 24 '20 at 22:50
  • You can pass object to `Link` see https://reacttraining.com/react-router/web/api/Link/to-object – gadi tzkhori Jan 25 '20 at 06:51

2 Answers2

0

Try to read the params in the constructor like this:

 constructor(props)
    {
        super(props)

        const { match: { params } } = this.props;

        var id = params.id

        
        this.state  = {
            id : id,
        }


    }

and then read the id from the state. If you want to pass the whole object you can send it through the url in base64 like this :

<Link to={`/details/+btoa( this.props.product )} >
      <img src={img} alt="product" className="card-img-top" />
  </Link>

And recieving it in the constructor like the previous snippet en parse it to string with the function atob() and then to json.

Saul Ramirez
  • 426
  • 2
  • 9
  • Hi Fernando, thanks for the suggestion, could you explain what you mean a little more? thanks – John Jan 24 '20 at 22:58
  • You want to send the whole object “product” to the other page right? – Saul Ramirez Jan 24 '20 at 23:10
  • Let me know if you need help. – Saul Ramirez Jan 24 '20 at 23:21
  • Yes, so I can then access its values – John Jan 24 '20 at 23:21
  • That’s right, you send the whole product object through the url and then read it in the other page. It is not that recommendable but it is funcional – Saul Ramirez Jan 24 '20 at 23:25
  • Hi, I think the product – John Jan 24 '20 at 23:28
  • You have to convert the object to string, like this: – Saul Ramirez Jan 24 '20 at 23:32
  • Thanks, ok that works, but I'm still unclear as to the code for Details to retrieve the object. – John Jan 24 '20 at 23:37
  • Look in the detail page you gotta read the parameter that you send through the url, in order to do that use this code: – Saul Ramirez Jan 24 '20 at 23:44
  • constructor(props) { super(props) const { match: { params } } = this.props; var id = params.id Var productBase64 = atob(id) this.state = { id : id, } } – Saul Ramirez Jan 24 '20 at 23:45
  • constructor(props) { super(props) const { match: { params } } = this.props; var id = params.id var productBase64 = atob(id) var productObj = JSON.parse(productBase64) this.state = { product: productObj } } – Saul Ramirez Jan 24 '20 at 23:47
  • What happens if the id prop changes? it is a bad practice to read props from the constructor that can lead to bugs. better if you use global state that every component pulls the data by id that way it will be persistent on id change and on refresh.Using btoa is super unconventional. – gadi tzkhori Jan 25 '20 at 07:01
0

You need an extra parameter

<Route exact path="/details/:id/:title" component={Details} />


export default class Details extends Component {
  render() {
    return(
      <div>
        <h2>{this.props.match.params.id}</h2>
        <h2>{this.props.match.params.title}</h2>
      </div>
     );
  } 
}

// In Product component

<Link to={`/details/${ this.props.product.id }/${this.props.product.title}`} >
  <img src={img} alt="product" className="card-img-top" />
</Link>
Zohaib Ijaz
  • 21,926
  • 7
  • 38
  • 60