0

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"
  }
}

2
  • why do you have a redirect inside an ui component ? What version of react router are you using? submit package.json Commented Jun 17, 2017 at 17:36
  • Added package.json. I have a redirect because i want the homepage as a clean introduction UI, redirecting to search/results after i submitted a food query. Inside search/results, i want to still be able to do api calls. A bit like Google.com. github.com/hyrosian/nutrion is github link. Commented Jun 17, 2017 at 17:39

1 Answer 1

1

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
    });
}
Sign up to request clarification or add additional context in comments.

1 Comment

Oh ofcourse! Was lost complexity, all new for me.Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.