Reputation: 645
I have a Home component with a searchbar
.
const Intro = (props) => {
return (
<Searchbar
onSubmit={props.onSubmit}
onChange={props.onChange}
value={props.value}
header='Nutrion'>
</Searchbar>
)
}
Searchbar is a controlled component. It get's passed event handlers
handleSubmit(e) {
e.preventDefault()
this.setState({
food: this.state.value,
submitted: true
})
}
If the value inside Searchbar get's submitted, it sets statefood: this.state.value
and submitted: true
.
submitted && <Redirect to={{
pathname: `/search/results`,
search: `?food=${food}`,
}} />
Submitted true
triggers a redirect to Results component, passing along a query string with the submitted food in the searchbar.
componentDidMount() {
console.log('hiii')
const food = this.state.food || queryString.parse(this.props.location.search).food
fetchRecipes(food).then(recipes => {
if (recipes === null) {
return this.setState (
{
error: 'Server failed to respond. Please try again.',
loading: false
})
}
this.setState( {
error: null,
recipes: recipes,
loading: false,
isFetched: true
})
})
}
Here is the problem. This is the ComponentDidMount()
inside the redirected to class Results
. It takes the query string we passed earlier and parses it. The result of this is used for an API request and the returning data is passed to this.state.recipes
. Everything works. Data gets passed to the recipeList
{!this.state.loading && <Recipelist recipes={this.state.recipes} />}
But this only works on INITIAL render. If i change this.state.food by submitting the value inside (another) Searchbar inside Results, it doesn't re-request API data and update RecipeList with new Recipes. How can you make a new API request each item a new value is submitted to this.state.food
and re-render RecipeList?
I have posted links to relevant files below:
import React from 'react'
import { Redirect } from 'react-router-dom'
import Searchbar from './../ui/Searchbar'
import {
Jumbotron,
// PageHeader
} from 'react-bootstrap'
const Intro = (props) => {
return (
<Searchbar
onSubmit={props.onSubmit}
onChange={props.onChange}
value={props.value}
header='Nutrion'>
</Searchbar>
)
}
class Home extends React.Component {
constructor(props) {
super(props)
this.state = {
submitted: false,
food: '',
value: ''
}
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
this.setState({ value: e.target.value })
}
handleSubmit(e) {
e.preventDefault()
this.setState({
food: this.state.value,
submitted: true
})
}
render() {
// REMINDER: toegang tot path is via this.props.match => match.url object
const submitted = this.state.submitted
const food = this.state.food
return (
<Jumbotron>
{
!submitted &&
<Intro onSubmit={this.handleSubmit}
onChange={this.handleChange}
value={this.state.value}/>
}
{
submitted &&
<Redirect to={{
pathname: `/search/results`,
search: `?food=${food}`,
}} />
}
</Jumbotron>
)
}
}
export default Home
import React, {Component} from 'react'
import {Jumbotron} from 'react-bootstrap'
import Searchbar from './../../ui/Searchbar'
import { fetchRecipes } from './../../utils/api'
import queryString from 'query-string'
import Recipelist from './Recipelist'
class Results extends Component {
constructor(props) {
super(props)
this.state = {
value: '',
food: '',
recipes: null,
isFetched: false,
error: null,
loading: true
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(e) {
this.setState({ value: e.target.value })
}
componentDidMount() {
console.log('hiii')
const food = this.state.food || queryString.parse(this.props.location.search).food
fetchRecipes(food).then(recipes => {
if (recipes === null) {
return this.setState (
{
error: 'Server failed to respond. Please try again.',
loading: false
})
}
this.setState( {
error: null,
recipes: recipes,
loading: false,
isFetched: true
})
})
}
handleSubmit(e) {
e.preventDefault()
this.setState( {
food: this.state.value
})
}
render(){
if (this.state.loading) {
return <p> Loading ... </p>
}
if (this.state.error) {
return (
<div>
<p>{this.state.error}</p>
{/*<Link to='/'>try again</Link>*/}
</div>
)
}
return (
<div>
<Jumbotron>
<Searchbar
value={this.state.value}
onSubmit={this.handleSubmit}
onChange={this.handleChange}/>
</Jumbotron>
{!this.state.loading && <Recipelist recipes={this.state.recipes} />}
</div>
)
}
}
export default Results
{
"name": "nutrion",
"version": "0.1.0",
"private": true,
"dependencies": {
"normalize-css": "^2.3.1",
"prop-types": "^15.5.10",
"query-string": "^4.3.4",
"react": "^15.5.4",
"react-bootstrap": "^0.31.0",
"react-dom": "^15.5.4",
"react-router-dom": "^4.1.1",
"semantic-ui-react": "^0.68.5"
},
"devDependencies": {
"react-scripts": "1.0.7"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
Upvotes: 0
Views: 473
Reputation: 1115
You might be able to place a call to fetchRecipes(food) within the handleSubmit
handleSubmit(e) {
e.preventDefault();
let recipes = await = fetchRecipes(food);
let food = e.target.value;
this.setState( {
food, recipes
});
}
Upvotes: 1