2

I am trying to make a simple to-do/reminder single-page application using react. I want to add components dynamically to the page whenever data is submitted through a form. I have a flask backend set-up. This is the function called when the form is submitted:

submitNewReminder(event){
        event.preventDefault()
        let form = document.getElementById('new-reminder-form')
        const data = new FormData(form)
        const plainFormData = Object.fromEntries(data.entries());
        const JSONdata = JSON.stringify(plainFormData)

        fetch('http://localhost:5000/addrem',{
            method: 'POST',
            headers:{'Content-Type': 'application/json'},
            body: JSONdata,
        }).then(resp => resp.json().then(data =>{
                if (data){
                    this.response = data
                }
            }))

        this.setState({refresh:(this.state.refresh?0:1)})
        console.log(this.state.refresh)

    }

The response from backend contains all the reminders extracted from the database.

The state refresh is used to 'reload' the content of the page with the updated reminders. I toggle it between 1 and 0 so that the state gets updated and can re-render the component with added data each time a reminder is added. The render method looks like this:
render(){
        if (!this.state.isLoggedin && (this.state.refresh === 1 || this.state.refresh === 1)){
            return(
                <div>
                    <LoginForm do={this.submitForm} toggleSignup={this.toggleSignup}/>
                </div>
            )
        }
        else{
            return(
                <div className='container text-center'>
                    <h1>Logged in!</h1>
                    <div className="row">
                        { this.response.reminders.map((item,i=0) =>{
                                return <Card key={i++} reminder={item}/>
                            }
                        )}
                        <AddReminder addRem={this.toggleAddReminder} cancel={this.cancelAdd} submit={this.submitNewReminder}/>
                    </div>
                </div>
            )
        }
    }

With each reminder added, the a new <Card /> component is created which displays the data in it. This is the behaviour I want.

The Problem:

For the first submit of the form, no new cards/reminders are produced. But for the succeeding submits, a new card is displayed each time. I am unable to understand this behaviour. The console.log(this.state.refresh) shows that the first time it is submitted, the value of refresh remains 1 (refresh is initialised with value 1). Is there something wrong in my code? Is this the right method to achieve what I want?
  • Actually you don't really need refresh state. Just put the response in state(`this.state.reminders = response.reminders`) in `submitNewReminder` and also provided initial state to `reminders`, and use `this.state.reminders.map` instead and react will take care of re-rendering. – tarzen chugh Jul 27 '21 at 08:03
  • See the duplicate that I linked. Note: better NOT use the accepted answer, the poster accepted it incorrectly, other answers are better (see the score counters) – Peter B Jul 27 '21 at 08:10
  • I was referring to the accepted answer (vs the other answers there) in the duplicate link, not about anything posted here. – Peter B Jul 27 '21 at 08:26
  • @PeterB The link to the question you posted answered how some synchronous statements could be executed once the state was changed, explaining why `refresh` initially wouldn't change in my case. The problem with my code is that it won't re-render the component once the state was changed. Thanks for the input though! – Sinadin Shan Jul 27 '21 at 09:32

2 Answers2

1

might be a synchronisation problem. fetch is a async operation. the setState might be called before the data is uploaded and the response from the server is received. try to move the setState inside the .then block of the fetch function, so it gets called after the response is received. then the component can rerender with the new data.

DeepValue
  • 54
  • 4
1

You don't need refresh state

Highlights: Add the response in state and use state to render cards

Try below code:

state = {
  reminders: []
}

fetch('http://localhost:5000/addrem',{
            method: 'POST',
            headers:{'Content-Type': 'application/json'},
            body: JSONdata,
        }).then(resp => resp.json().then(data =>{
            if (data){
              this.response = data
              this.setState({
                reminders: this.response.reminders
              })
            }
          }))

{
  this.state.reminders.map((item,i=0) =>{
      return <Card key={i++} reminder={item}/>
  })
}

P.S - Don't use map iteration(i) as the key, use attribute from the reminders array that uniquely identifies the card.

Dharman
  • 30,962
  • 25
  • 85
  • 135
tarzen chugh
  • 10,561
  • 4
  • 20
  • 30