claudiopb
claudiopb

Reputation: 1090

ReactJS - Issues about Dynamic Routes

I have these components. I want to turn every into a dynamic url. For example, when accessing in the browser, http://localhost:3000/houses/1 I want to appear the House 1.

The other things in the application are working fine. I just want to solve this problem of implementing dynamic routes.

The data is fetched from a json file

db.json file

[
  {
    "houseId": 1,
    "name": "House 1",
    "photos": [
      "house1_001.jpg",
      "house1_002.jpg",
      "house1_003.jpg",
      "house1_004.jpg"
    ]
  },
  {
    "houseId": 2,
    "name": "House 2",
    "photos": [
      "house2_001.jpg",
      "house2_002.jpg",
      "house2_003.jpg",
      "house2_004.jpg"      
    ]
  },
  {
    "houseId": 3,
    "name": "House 3",
    "photos": [
      "house3_001.jpg",
      "house3_002.jpg",
      "house3_003.jpg",
      "house3_004.jpg"     
    ]
  } 
]

Router Component

    import React from 'react';
    import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'

    import App from './App'
    import Intro from './Intro'
    import Houses from './Houses'
    import House from './House'


    export default props => (
      <Router>
        <Route exact path='/' render={() => <App />} >
          <Route exact path='/intro' render={() => <Intro />} />
          <Route exact path='/houses' render={() => <Houses />} />
          <Route exact path='/houses/:houseId' render={(props) => <House {...props} />} />
        </Route>
      </Router>
    )

Houses Component

import React, { Component } from 'react'
import House from './House'

var data = require('./db.json');

class Houses extends Component {
  constructor(props) {
    super(props);
    this.state = {
      houses: []
    };
  }

  componentDidMount() {
    this.setState({
      houses: data
    })
  }

  render() {
    const { houses } = this.state;
    return (
      <div className="content house">
        {
          houses.map((house, index) => {
            return (
              <div>            
                <House house={house} />
              </div>
            )
          })
        }
      </div>
    )
  }
}

export default Houses


**House Component**

import React, { Component } from 'react';

class House extends Component {
  constructor(props) {
    super(props)
    this.state = {
    houseId: ""
    }
  }

  componentDidMount() {
    this.setState({
      houseId: this.props.match.params.id
    })
  }

  render() {
    return (
      <div>
        <h3>{this.props.house.name}</h3>
        <ul>
          {this.props.house.photos.map((photo, index) => {
            return (
              <li><img src={`/images/${photo}`} /></li>
            )
          })
          }
        </ul>
      </div>
    )
  }
}


export default House;

House component

import React, { Component } from 'react';

class House extends Component {
  constructor(props) {
    super(props)
    this.state = {
    houseId: ""
    }
  }

  componentDidMount() {
    this.setState({
      houseId: this.props.match.params.id
    })
  }

  render() {
    return (
      <div>
        <h3>{this.props.house.name}</h3>
        <ul>
          {this.props.house.photos.map((photo, index) => {
            return (
              <li><img src={`/images/${photo}`} /></li>
            )
          })
          }
        </ul>
      </div>
    )
  }
}


export default House;

Upvotes: 0

Views: 62

Answers (3)

Junius L
Junius L

Reputation: 16122

Pass the json data to <House/> component and use the id to display the correct data.

import React, { Component } from 'react';
const data = require('./db.json');

class House extends Component {
  constructor(props) {
    super(props)
    this.state = {
      houses: data,
    }
  }

  render() {

    const houseId = this.props.match.params.houseId;

    return (
      <div>
        <h3>{this.state.houses[houseId].name}</h3>
        <ul>
          {this.state.houses[houseId].photos.map((photo, index) => {
            return (
              <li><img src={`/images/${photo}`} /></li>
            )
          })
          }
        </ul>
      </div>
    )
  }
}


export default House;

Create two components, one will be rendered in Houses and one will be render on house/1

 // rendered inside Houses
 class House extends Component {

  render() {
    return (
      <div>
        <h3>{this.props.house.name}</h3>
        <ul>
          {this.props.house.photos.map((photo, index) => {
            return (
              <li><img src={`/images/${photo}`} /></li>
            )
          })
          }
        </ul>
      </div>
    )
  }
}

HouseInfo, which display data by query parameter

import React, { Component } from 'react';
const data = require('./db.json');

class HouseInfo extends Component {
  constructor(props) {
    super(props)
    this.state = {
      houses: data,
    }
  }

  render() {

    const id = this.props.match.params.houseId;
    const houseId = id >= 1 ? id - 1 : 0; 

    return (
      <div>
        <h3>{this.state.houses[houseId].name}</h3>
        <ul>
          {this.state.houses[houseId].photos.map((photo, index) => {
            return (
              <li><img src={`/images/${photo}`} /></li>
            )
          })
          }
        </ul>
      </div>
    )
  }
}

export default HouseInfo;

Router

import React from 'react';
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'

import App from './App'
import Intro from './Intro'
import Houses from './Houses'
import House from './House'
import HouseInfo from './HouseInfo'


export default props => (
  <Router>
    <Route exact path='/' render={() => <App />} >
      <Route exact path='/intro' render={() => <Intro />} />
      <Route exact path='/houses' render={() => <Houses />} />
      <Route exact path='/houses/:houseId' render={(props) => <HouseInfo {...props} />} />
    </Route>
  </Router>
)

Upvotes: 1

jank
jank

Reputation: 860

I don't see what props you are passing to the House component but my guess is not exactly intended ones. Try this:

import { withRouter } from 'react-router-dom';
...
export default withRouter(Houses);

or without withRouter:

  <Route exact path='/houses/:houseId' render={House} />

and in your Route your param value is specified as houseId, as it should be in House component:

this.setState({
  houseId: this.props.match.params.houseId
})

Upvotes: 0

ThayalanGR
ThayalanGR

Reputation: 143

Entire snippet is right except the thing is that you have wrongly matched the params id, change the following code in house component

this.setState({
  houseId: this.props.match.params.houseId
})

you have to use the same param id ie.,houseId inside the component

using the houseId in the state ie.,(this.state.houseId) in House component, loop through the json data and find the houseId and display the corresponding data.

Upvotes: 0

Related Questions