Reputation: 433
I'm trying to create a list of houses and each house upon clicking will point to a separate page with data on that house. Currently all the data is static data I created in my constructor - named leaseData
. I want the Route path
to point to /dashboard/lease-id
. I'm trying to pass both the address and the monthlyRent into the Lease
component so that I can render that data in the new component. How do I do this?
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import { Lease } from './Lease'
class Dashboard extends Component {
constructor(props) {
super(props)
this.match = this.props.match
this.leaseData = [
{
id: 1,
address: '18291 Rainbow Dr, Cool Springs CA 93102',
monthlyRent: 4300
},
{
id: 2,
address: '2200 Stiller Dr, Las Vegas NV 96274',
monthlyRent: 1500
},
{
id: 3,
address: '21626 Sleepy Hollow Ct, Walnut CA 91763',
monthlyRent: 2400
}
]
}
render() {
let linkList = this.leaseData.map(lease => {
return (
<li>
<Link to={`${this.match.url}/${lease.id}`}>
<img src="https://cdn.edinarealty.com/media/2256/homepage-tiles_new-construction.jpg" alt="HTML5 Icon"></img>
</Link>
</li>
)
})
return (
<div>
MAIN DASHBOARD
<ul>
<li> {linkList} </li>
</ul>
<Route path={`${this.match.url}/:lease-id`} render={<Lease data={}/>}/>
</div>
)
}
}
Upvotes: 0
Views: 1166
Reputation: 15688
Let's try to separate the App and Dashboard logic so we can render things more cleanly.
Here's a sandbox for reference: https://codesandbox.io/s/suspicious-merkle-4bxv3
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route } from "react-router-dom";
import Dashboard from "./Dashboard";
import Lease from "./Lease";
import "./styles.css";
class App extends React.Component {
state = {
leaseData: [
{
id: 1,
address: "18291 Rainbow Dr, Cool Springs CA 93102",
monthlyRent: 4300
},
{
id: 2,
address: "2200 Stiller Dr, Las Vegas NV 96274",
monthlyRent: 1500
},
{
id: 3,
address: "21626 Sleepy Hollow Ct, Walnut CA 91763",
monthlyRent: 2400
}
],
selected: null
};
changeSelected = id => {
this.setState({
selected: this.state.leaseData.find(lease => lease.id == id)
});
};
render() {
return (
<BrowserRouter>
<Route
path="/"
exact
render={props => <Dashboard data={this.state.leaseData} />}
/>
<Route
path="/lease/:id"
render={props => (
<Lease
{...props}
selected={this.state.selected}
changeSelected={this.changeSelected}
/>
)}
/>
</BrowserRouter>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
import React, { Component } from "react";
import { Link } from "react-router-dom";
class Dashboard extends Component {
render() {
let linkList = this.props.data.map((lease, index) => {
return (
<li key={index}>
<Link to={`/lease/${lease.id}`}>
<img
src="https://cdn.edinarealty.com/media/2256/homepage-tiles_new-construction.jpg"
alt="HTML5 Icon"
/>
</Link>
</li>
);
});
return (
<div>
MAIN DASHBOARD
<ul>{linkList}</ul>
</div>
);
}
}
export default Dashboard;
import React, { useEffect } from "react";
import { Link } from "react-router-dom";
const Lease = props => {
useEffect(() => {
const id = props.match.params.id;
props.changeSelected(id);
}, []);
const { selected } = props;
if (!selected) {
return <div>Loading...</div>;
} else {
return (
<div>
<Link to="/">Back to home</Link>
<h4>Id: {selected.id}</h4>
<h4>Address: {selected.address}</h4>
<h4>Rent: {selected.monthlyRent}</h4>
</div>
);
}
};
export default Lease;
Main notes:
render
prop we can pass in data from
the App-state, to the component of the Route
. For the Dashboard Route, we pass in the entire lease-data
. For the Lease route, we pass in the changeSelected()
to help retrieve the selected lease item, and selected
which is that found item. Additionaly, we spread {...props} to get access to props like match
and history
.Lease
component, we fire the changeSelected
function. This happens in useEffect()
, we use props.match.params.id
to get the id of the lease (also in the URL) we navigated to via Link
. selected
value in the App-state with the desginated lease-object in our list.App.js
gets re-rendered (due to state-change) and passes down the selected
item state-value to Lease
, which we will use to display the information on that lease object.Overall it's a clean-way of doing this before integrating redux.
Upvotes: 1
Reputation: 11760
Extract data from Dashboard
this will let us the ability to look for it by id when Lease
component mounts
You can replace it with an api call when you implement the backend
const data = [
{
id: 1,
address: "18291 Rainbow Dr, Cool Springs CA 93102",
monthlyRent: 4300
},
{
id: 2,
address: "2200 Stiller Dr, Las Vegas NV 96274",
monthlyRent: 1500
},
{
id: 3,
address: "21626 Sleepy Hollow Ct, Walnut CA 91763",
monthlyRent: 2400
}
];
Extract the leaseId from match.params.leaseId
and look it up when the component mounts using useEffect
with leaseId
as a dependency
When you have the api ready you can just replace data.find
with an API call with the leaseId
The reason 'im looking it up on mount is that it will give us the ability to go straight to the URL without needing to go through the dashboard to load the data
const Lease = ({
match: {
params: { leaseId }
}
}) => {
const [leaseData, setLeaseData] = useState(null);
useEffect(() => {
setLeaseData(data.find(d => d.id.toString() === leaseId));
}, [leaseId]);
if (!leaseData) return null;
return (
<div>
<h1>{leaseData.id}</h1>
<p>{leaseData.address}</p>
<p>{leaseData.monthlyRent}</p>
</div>
);
};
When the url is /dashboard
use the render prop to render the main Dashboard
and create a Route
path to leaseId
const Dashboard = ({ match: { url } }) => {
const linkList = data.map(lease => {
return (
<li key={lease.id}>
<Link to={`${url}/${lease.id}`}>
<img
src="https://cdn.edinarealty.com/media/2256/homepage-tiles_new-construction.jpg"
alt="HTML5 Icon"
/>
</Link>
</li>
);
});
return (
<Switch>
<Route
exact
path={url}
render={() => (
<div>
MAIN DASHBOARD
<ul>{linkList}</ul>
</div>
)}
/>
<Route path={`${url}/:leaseId`} component={Lease} />
</Switch>
);
};
const Home = () => (
<div>
<Link to="/dashboard">Dashboard</Link>
</div>
);
const App = () => (
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/dashboard" component={Dashboard} />
</Switch>
</Router>
);
Upvotes: 0
Reputation: 407
You could use a router switch and generate your lease routes like so:
import React, { Component } from 'react'
import { Switch, Link, Route } from 'react-router-dom'
import { Lease } from './Lease'
class Dashboard extends Component {
constructor(props) {
super(props)
this.match = this.props.match
this.leaseData = [
{
id: 1,
address: '18291 Rainbow Dr, Cool Springs CA 93102',
monthlyRent: 4300
},
{
id: 2,
address: '2200 Stiller Dr, Las Vegas NV 96274',
monthlyRent: 1500
},
{
id: 3,
address: '21626 Sleepy Hollow Ct, Walnut CA 91763',
monthlyRent: 2400
}
]
}
render() {
let linkList = this.leaseData.map(lease => {
return (
<li>
<Link to={`${this.match.url}/${lease.id}`}>
<img src="https://cdn.edinarealty.com/media/2256/homepage-tiles_new-construction.jpg" alt="HTML5 Icon"></img>
</Link>
</li>
)
})
let leaseRoutes = this.leaseData.map(lease => <Route exact path={`${this.match.url}/${lease.id}`} render={<Lease data={lease}/>}/>)
return (
<div>
MAIN DASHBOARD
<ul>
<li> {linkList} </li>
</ul>
<Switch>
{leaseRoutes}
</Switch>
<Route path={`${this.match.url}/:lease-id`} render={<Lease data={}/>}/>
</div>
)
}
}
Upvotes: 0