So let's work on the front end again
and let's give the users some feedback
about what's going on.
For this I'll use a similar approach
as I did earlier in the course.
I'll show some notifications.
For a dis-a-tach,
you find a UI zipped file, which you can extract
and then just move into your components folder.
It's a folder, a UI folder.
Then with one component in it,
the notification component, with some styles.
And if you followed along with the previous core sections
this will look fairly familiar.
That's a notification which we can show
at the bottom of the screen to give to users
some indication for Weber Data is on its way,
it's exceeded, or if the request failed.
And I wanna utilize this again now.
Now before in this course,
we implemented this with context, with the context API.
I used context there because we triggered this notification
from different places in our application.
Here in this blog project,
we actually don't have that scenario.
Here, we actually only need to do a notification
for the contact form.
We could still use context though
to make this more versatile
and allow using it in different parts.
But we could also just use notification,
this component in the contact form component only.
And not set up context and all the other parts to manage it.
And I will do that.
I will just use it locally here,
but of course as an extra exercise,
definitely also feel free to use context again,
just as we did it earlier in the course.
Now as I said I'll use it locally though
And therefore in the contact form component,
I'll import notification from
going up one level UI notification.
And the goal is to show it whilst the request is on its way
and also once it's done.
Once we have a success or an error.
That means that we need a new piece of state here.
We need to find out what our current state is.
So add use state and don't set any initial value
but I'll name it,
request status and set request status.
And request status can be pending, success or error.
That's my definition.
So pending, success or error.
That are the three possible values we can save in there
or no undefined initially
if we have no ongoing or finished request.
Okay. So now we wanna set the request status,
as we send our request here.
Now I used fetch with then
and catch in the previous core sections,
and we could do this here as well,
but to mix things up and because it's a bit more convenient
to work with fetch when using async/await,
I will use async/await here.
And I'll turn the sent message handler function
into an async function
which allows me to use the await keyword here.
Then we get the response here
and we can use the response thereafter.
Now from the response we want to get the data
by awaiting response, JSON, and now
that's the part where async/await is more convenient.
We can check if response okay is not true.
So if not response okay, which means we have an error.
In this case I will throw a new error
where I set my message equal to data message,
if our response data has a message
or two something went wrong as a fallback.
Else, thereafter we know that everything worked.
Now to not have all this age to DP logic in here,
and to be able to conveniently
try catch the entire HTTP block in one go,
I will grab that code here,
where we fetch and parse the data
and handle the not okay case
and cut debt and move it into a separate function.
A function which we can add
in that same contact form JS file
or a function which we could add in a different file.
Here I'll add it in the same file
and add my async send contact data function.
So async function sent contact data.
And here I now just expect that I get the contact details
as argument and data send the object
which will be added as a body
converted to JSON of course the contact details.
So now I have to logic in here
and now in sent message handler,
we just need to await, send contact data
and pass our object where we set the email to
entered email ends on to that function here.
So here name is set to entered name
and message is set to entered message like this.
Now we still await this, because that's a async function
and we also use await in here.
We could return the data here,
the parse response stayed up,
but since I don't care about it here in this component,
we don't really need to.
So now we got that.
Now that's a bit leaner.
And now, before we send the contact data,
I wanna set my request status.
So update this state here, Q pending.
So I'll set it to pending.
Now once we're done,
thereafter, I wanna send it, set it to success.
If that fails, I wanna set it to error
and hence I'll try this,
here and catch any errors that might be frowned
from anywhere in this request
and set the request status to error.
And hence success is not set thereafter
because dented would also be set if we had an error,
but here inside of try.
Now we have these different status updates
and now we can use them to show our notification.
Now to show the notification,
I wanna render this notification component
which we are already importing based on the status
and based on the status also with different data.
For this in this contact form component function,
I wanna derive the data for my notification.
I'll add a notification data variable
and initially it's undefined.
We can also just name it notification.
But then I'll check if request status is equal to pending
and if that's the case,
I'll set notification equal to an object,
where the status is set to pending,
the title is set to sending message,
and the message of this notification could be set to
your message is on its way.
Now, if request status is equal to success
I wanna set notification to a different object.
Then notification should be set to an object.
Where the status of course is success
where to title is success like this
and where the message is,
message sent successfully.
And last but not least,
the last data package I wanna infer is
for requests status equal to error.
In that case, I wanna set my notification equal to
a status where I set error, a title of error
and now to get the error meagerness
we actually need to get it out of this error object
and set a separate state for that.
So add a new state here, use state request,
error, state and a set request, error updating function.
Initially it's undefined.
But if we have a request error here,
I'll set my request error to
the error message I get here.
So then here, when we derive the data for the notification,
we can set message equal to request error like this.
Okay so now we got the data for the notification
and we could break this component
into multiple smaller components if we wanted to
since it's getting a bit bigger
but I'll leave it as one component for the moment.
Now we have that different data.
We have the different pieces of data.
Now we wanna render the notification
if we do have a notification to show.
So in the end if notification is anything but undefined.
Because if it is undefined there is nothing to show.
So then here in this section, for example
we can add a conditional content and check for notification.
And if it's truthy, we rendered the notification component
and we set status equal to notification dot status.
And we set title equal to notification dot title.
And we set message equal to notification dot message.
Like this and status title and message are the props
I'm expecting inside of that notification component.
So we have to set them here.
So that should now be working with all that work done.
If we now reload and I again enter something here.
Test for click sent message we see that
sending state and then the success state.
Now it never disappears at the moment
but that's something we can also implement
with help of useEffect as we saw earlier in the course.
We can run a function whenever the request status changes
and if it changed to success or error,
then we want to reset it to undefined after three seconds
let's say, and that will then re render this component
and get rid of our notification.
So here we can execute useEffect
and define an effect function and the dependencies.
And here in useEffect I wanna check if requests status
is equal to pending,
or if requests status is equal to error.
So if it's either off the two, then if that is the case
I want to set a timer to reset my request status.
So then I'll set a timeout here, to three seconds
and after three seconds, this function will execute
and there I'll set request status to null.
Reset it basically.
We can also set request set request error to null here
to reset this as well.
And now request status is a dependency of useEffect,
so that this effect function will re execute
whenever the request status changes
and only when that changes.
So when we change entered email
because we type into email field,
we will not execute this again.
Now if it executes again and we have a ongoing timer
I wanna get rid of the existing timer though
and hence I'll store a reference in a constant here
and return that cleanup function
where I call clear timeout and clear that timer.
If that in fact should rerun
whilst we have an ongoing timer.
And of course here I don't wanna check
for requests status pending but success I mean.
So success or error.
If the requests status is anything else
we don't do anything.
Okay. So now if we saved this, it should disappear.
Let me also open up the Dev Tools
to see if we got any errors there.
Max, another try.
Click send message,
sending success and it disappears.
And if I hammered this button and I sent multiple messages
it's still only disappears once after three seconds
because the timers get cleared.
So that is working.
All that data also did end up here on MongoDB.
If we refresh we see all those messages here
so that worked.
And therefore now we all just show some feedback.
Let's now see if it also works if something breaks.
For this I'll go to the API route and break my credentials
Like this saved as
and try sending this request again.
And then we have that error case here.
Which also disappears after three second though.
So that's also working and with that, let's fix it again.
So this all works.
As a last step,
we maybe wanna clear the user input after it was sent
and for this back in the contact form,
we can basically go here
where we set the request status to success
and say that if the request is a success,
we wanna clear what the user entered.
Because then the message was sent
and the input isn't needed anymore.
So here we could set entered message
to an empty string again,
set entered email email to an empty string
and set entered name to an empty string.
Since we're binding all those state values
back to the inputs here and here and here.
If we change the state
those changes will be reflected in the inputs.
So if we do that, then if I reload again
and again enter something here,
A last try
then if I click send message you'll see that
the input disappears as soon as we have a success.
And therefore now this is the final state
of this contact form and of the overall blog.
At least when it comes to what we see on the screen.