React Flash Message: How to make the message show without refreshing the page but refresh on 200
Asked Answered
D

2

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?

Demise answered 29/11, 2020 at 16:17 Comment(11)
When you click submit you mean it rerenders the component or reload the page?Alrick
my bad, I want to rerender the component so it displays the correct dataDemise
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?Alrick
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?Demise
"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?Glutamate
@LajosArpad Some errors returned from backend like "There's error in your form" or "Connection Timeout" or simple msg like thatDemise
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 thoughDemise
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.Glutamate
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 thisPlanography
@NtshemboHlongwane yea, like an alert bannerDemise
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 solutionPlanography
S
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.

Swede answered 11/12, 2020 at 3:27 Comment(2)
option 2 is a bad idea if multiple persons can send a post request!Bushing
good point, option 2 might have stale data. It's better to always re-fetch.Swede
B
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!

Bushing answered 12/12, 2020 at 20:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.