7

I want to show error (or success) message using FlashMessage while having my page reload at desired time

I'm using FlashMessage and my code looks like

render() {
  return (
    {this.state.error ? <FlashMessage duration={5000}><strong>{this.state.error.message}</strong></FlashMessage> : ''}
    //Some table here presenting data
    <Button variant="outline-info" type="submit" size="lg" block className="button-custom" onClick={this.handleSubmit.bind(this)}>
          Submit
        </Button>
  )}

for my stateful component, the error is loaded by

handleSubmit(event) {
let data = {
  name: this.state.name,
  unit_price: this.state.unit_price,
  length: this.state.length,
  time: this.state.selectedDate,
  instructor: this.state.instructor,
}
ApiService.postLesson(data)
.then(res => {
  this.setState({
    message: 'Success!'
  });
})
.catch(error => {
  this.setState({
    message: error,
    error: error,
  });
  console.log(error);
})

};

and my ApiService.postLesson is

const instance = axios.create({
  headers: {
    "Content-Type": "application/json",
    Authorization: 'Token ' + localStorage.getItem('token')
  },
});
export default {
  postLesson: data => 
    instance({
        'method': 'POST',
        'url': BACKEND_LESSONS_URL,
        'data': data
    }),
  // some other services

Now my problem is every time I click Submit, whether it's successful or not, it reloads the page. Because of that, I think my state is reloaded and the error is gone. If I add event.preventDefault() in handleSubmit, then I can see the message but then my content in the table would not be updated. What's a solution for this?

JChao
  • 2,178
  • 5
  • 35
  • 65
  • 2
    When you click submit you mean `it rerenders the component` or `reload the page?` – Christian LSANGOLA Nov 29 '20 at 16:22
  • 1
    my bad, I want to rerender the component so it displays the correct data – JChao Nov 29 '20 at 17:40
  • 2
    So you've said the if you do `event.preventDefault()` the table won't update.Normaly when you retreive some data from the server.That means that you have some initial data that is getting rendered in your component that you retreived using the `componentDifMount()` `method`.So if you want to update your data, the logging of updating the state should be done by making some comparison with a previous `state`.Have you used the life `cycle method` that udated the state? – Christian LSANGOLA Nov 29 '20 at 18:11
  • yes, the data is loaded in `componentDidMount` indeed. I'm a little confused where/when the update should happen and how to compare the previous state in this case. The error is returned as an async call, so the state is set some time after. Should I use `shouldComponentUpdate` and compare the previous state's error and current state's error? – JChao Nov 29 '20 at 20:31
  • "my bad, I want to rerender the component so it displays the correct data" is the page reloaded? What is the error message when you manage to see it? – Lajos Arpad Dec 06 '20 at 10:29
  • @LajosArpad Some errors returned from backend like "There's error in your form" or "Connection Timeout" or simple msg like that – JChao Dec 06 '20 at 10:39
  • My current solution uses event.preventDefault() and then force change the message in my state. If the POST is success, I call the API again to load the data. Not sure if this is the best approach though – JChao Dec 06 '20 at 10:40
  • The error message is the most important in detecting what your issue is. It is quite possible that you have two issues and you would need to first fix your request. Timeout might happen on your client-side, since you have a duration for the FlashMessage. The error on your form might also be given by the client-side. So your best interest would be to first find out whether the request ever makes it to the server. It's possible that you have an issue on the client-side and another on server-side. However, if you have an issue on the server-side, that might affect your client-side. – Lajos Arpad Dec 06 '20 at 11:01
  • By flash message you talking sort of like a notification when some interaction happens? If yes then I think I have a simpler solution to this – Ntshembo Hlongwane Dec 07 '20 at 13:05
  • @NtshemboHlongwane yea, like an alert banner – JChao Dec 07 '20 at 17:17
  • I have never used ```FlashMessage``` before(And this question was asked long ago so I thought maybe an alternative solution would be helpful) but I do know of an alternative so I do not know if you want me to share that solution? If yes the specify then I will give solution – Ntshembo Hlongwane Dec 07 '20 at 17:20

2 Answers2

4

Seems like you are on the right track and event.preventDefault() is really necessary for what you are trying to achieve.

So, you can refresh the page on success by calling location.reload():

handleSubmit(event) {
  event.preventDefault();
  let data = {
    name: this.state.name,
    unit_price: this.state.unit_price,
    length: this.state.length,
    time: this.state.selectedDate,
    instructor: this.state.instructor,
  }
  ApiService.postLesson(data)
    .then(res => {
      this.setState({
        message: 'Success!'
      });
      location.reload(); // refreshes the page
    })
    .catch(error => {
      this.setState({
        message: error,
        error: error,
      });
      console.log(error);
    })
}

It's not clear why do you need to refresh the entire page and bootstrap react app after successful postLesson() calls. However, there are potentially better options for your case:

  1. re-fetching the list of items displayed in table view
  2. or adding new lesson to the list on 200 response
handleSubmit(event) {
  event.preventDefault();
  let data = {
    name: this.state.name,
    unit_price: this.state.unit_price,
    length: this.state.length,
    time: this.state.selectedDate,
    instructor: this.state.instructor,
  }
  ApiService.postLesson(data)
    .then(res => {
      this.setState({
        message: 'Success!'
      });
      // 1. re-fetching list of items
      // ApiService.getLessons().then((lessons) => {this.setState({lessons})})

      // or 2. add newly posted lesson to the list 
      // this.setState({lessons: this.state.lessons.concat(data)})
    })
    .catch(error => {
      this.setState({
        message: error,
        error: error,
      });
      console.log(error);
    })
}

I hope this gives you a few ideas.

0
handleSubmit(event) {
  // to prevent the reload!
  event.preventDefault();
  let data = {
    name: this.state.name,
    unit_price: this.state.unit_price,
    length: this.state.length,
    time: this.state.selectedDate,
    instructor: this.state.instructor,
  }
  ApiService.postLesson(data)
    .then(res => {
      this.setState({
        message: 'Success!'
      });
      // TODO: call the /lessons endpoint and set the state with the result!
      /* WARNING: do not add the lesson manually to the state without fetching
       * the lessons endpoint specifically if more than one person can do the 
       * update because you will see stale data!!!!
       */
    })
    .catch(error => {
      this.setState({
        message: error,
        error: error,
      });
      console.log(error);
    })
}

in the TODO comment, call your main endpoint (/lessons for example) and set the data in the state so the view will get updated without refreshing the whole page!

cl3m3c7
  • 141
  • 6