Reputation: 841
A little context, I am trying to build a small property site.
On my home component/page, I have a form component. When inputs are completed and submit is clicked, the page is pushed to the list page with the inputs attached to the URL using
this.props.history.push(`/listing/${sleeps}/${startDate}/${endDate}`);
On the listing component/page, a fetch request is made using data from (this.props.match.params) which then updates state with details from fetch. The state is then passed on as props to a map component which creates markers and a list component which creates a list of properties.
On the listing component/page, I have included the form component for users to update their search, however, when submit is clicked, the URLs update but match.params don't, so fetch doesn't run.
How can I update the params and call fetch with the new data whilst staying on the same page?
///FORM COMPONENT///
import React, {Component} from 'react';
import {withRouter} from 'react-router-dom';
class Form extends Component {
constructor(props) {
super(props);
this.state = {
sleeps: "",
startDate: "",
endDate: ""
}
}
render () {
const {sleeps, startDate, endDate} = this.state;
return (
<div>
<form
name="myForm"
autoComplete="off"
onSubmit = {(e) => {
e.preventDefault();
this.props.history.push(`/listing/${sleeps}/${startDate}/${endDate}`);
}}>
<input
name="sleeps"
type="text"
required
value={sleeps}
onChange = {(e) => {
this.setState({sleeps: e.target.value});
}}
/>
<input
name="startdate"
type="text"
required
placeholder="yyyy-mm-dd"
value={startDate}
onChange = {(e) => {
this.setState({startDate: e.target.value});
}}
pattern="(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))"
/>
<input
name="enddate"
type="text"
required
placeholder="yyyy-mm-dd"
value={endDate}
onChange = {(e) => {
this.setState({endDate: e.target.value});
}}
pattern="(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))"
/>
<button
type="submit"
id="submit">
click
</button>
</form>
</div>
)
}
}
export default withRouter(Form);
///LISTING COMPONENT///
import React, {Component} from 'react';
import MapList from './MapList';
import List from './List';
import Form from './Form';
class Listing extends Component {
_isMounted = false;
constructor(props) {
super(props);
this.state = {
mapLatLng: [],
listInfo: []
}
}
getData = () => {
const {sleeps, start, end} = this.props.match.params;
const params = `sleeps=${sleeps}&startdate=${start}&enddate=${end}`
fetch(url + params)
.then(response => {
if (response.ok) {
return response.text()
}
})
.then(xml => {
return new DOMParser().parseFromString(xml, "application/xml")
})
.then(data => {
//...data
if (this._isMounted) this.setState({mapLatLng:mapData, listInfo:listData});
})
.catch(err => {
console.log(err);
});
}
componentDidMount = () => {
this._isMounted = true;
this.getData();
}
componentWillUnmount = () => this._isMounted = false;
render () {
return (
<div>
<Form />
<List data={this.state.listInfo} />
<div className="map-container">
<MapList data={this.state.mapLatLng} />
</div>
</div>
)
}
}
export default Listing;
///EDIT///INCLUDING APP/ROUTER
import React, {Component} from 'react';
import Listing from './Listing';
import Single from './Single';
import Home from './Home';
import {Switch, Route, Link} from 'react-router-dom';
import './App.css';
class App extends Component {
render () {
return (
<div>
<Link to="/listing"><p>listings</p></Link>
<Link to="/"><p>home</p></Link>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/listing/:sleeps/:start/:end" component={Listing} />
<Route path="/:id" component={Single} />
</Switch>
</div>
)
}
}
export default (App);
Upvotes: 0
Views: 1567
Reputation: 1211
You should use componentDidUpdate
to get a new data according to your router config. Listing component:
componentDidUpdate(prevProps) {
if (prevProps.match.params !== this.props.match.params) {
this.getData();
}
}
You've got a loop in componentDidUpdate
since you try to get a data every time when the component updates.
Upvotes: 1
Reputation: 324
//In your listing component you can pass the getData function in your form component
constructor(props) {
super(props);
this.state = {
mapLatLng: [],
listInfo: []
}
this.getData = this.getData.bind();
}
render () {
return (
<div>
<Form getData={this.getData} />
<List data={this.state.listInfo} />
<div className="map-container">
<MapList data={this.state.mapLatLng} />
</div>
</div>
)
}
// Then in your form comppnent you can call get data on submit
<form
name="myForm"
autoComplete="off"
onSubmit = {(e) => {
e.preventDefault();
this.props.history.push(`/listing/${sleeps}/${startDate}/${endDate}`);
this.props.getData();
}}>
Upvotes: 1
Reputation: 485
From what I understand, you will have to run getData
again in componentDidUpdate
in your listing component (Docs) when your URL props change.
Upvotes: 1