Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
English
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranรฎ)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
Now, we don't just have the quotes,
we also have the comments.
And here we're not really sending
or storing or using any comments.
That's the last thing I wanna change here.
For this we can start in this comments component here.
There we have this button
which allows us to start adding comments,
and that will then render this new comment form here.
Now, this new comment form here
actually has this submit form handler,
where we wanna, well, send our comment data to a server.
And therefore we can do that.
We can import the use HTTP hook again
from going up to hooks, use HTTP,
and import a function from that API file, to be precise,
it's the add comment function.
And then here in the new comment form component
we can call our custom hook and pass, add comment to it,
so a pointer at this function.
And then just get back the send request function
and the status.
And then here,
I wanna send my request in the submit form handler.
Now, this request, which we're sending here,
this add comment function wants to comment data
and the quote ID to which this comment belongs,
because every comment is mapped to a specific quote.
Now, therefore in this new comment component here,
for a send request, here to send request,
I wanna pass an object with my comment data,
and here I'll keep it simple in a comment,
we'll just have a text field
which then holds this entered text
which we can get like this by adding an enter text constant
where I get the entered text from my comment text ref.
So from this ref, which is connected to this text area here,
and then there with.current.value
we can get the entered value,
and that's then the text which I send with my request.
With that, the status will also change.
It will change to pending
as long as the request is on its way.
And we can utilize this to output some loading spinner here.
Instead of the form,
we can check if status is equal to pending.
And if that's the case,
then I output a div here with a class name
of centered and the loading spinner inside of it.
So now we'll show a little loading spinner
on top of this form, as long as the request is on its way.
Now, once the request is done,
I wanna notify the comments component,
so the parent component of this component
that we're done adding a comment.
For this, we can use the use effect hook here,
and register a new effect
in this new comment form component.
And the fact which should trigger
whenever our status changes.
And here I'll simply check
if the status is equal to complete it.
And we also might wanna check
if we don't have an error here,
simply by also using this error data piece which we get.
So here, I'll also add this as a dependency
and check that we're done and we don't have an error.
And then in here, I wanna call a function
which I expect to get fruit props
to notify the parent component,
with just this comments component, about the fact
that we're done adding a new comment,
and data should re-fetch comments therefore.
We can do this by extracting a prop from our props,
maybe a prop named on added comment,
and then calling this here as a function,
and adding it as a dependency to this array of dependencies.
So I expect that on this prop,
I get a function and I call this function
once we're done adding a comment.
And then we can do whatever we wanna do when that happens
in the parent component,
which does define that function we get here.
Now, before that'll work though,
there's one more thing we have to do here
on send request, actually.
We're sending a request with our comment data,
but keep in mind that add comment also wants the quote ID.
So we also need to send the quote ID along.
And for getting access to this ID, we got two options.
We can use the use parents hook
which we import from react router dom.
This gives us access
to the currently active params in the URL.
And we can use this in any component.
So also in this nested form component.
And that would then give us quick and easy access
to the active quote ID.
It of course means that we're now only able
to use this new comment form component
in a place where the URL will contain that quote ID.
We can't embed it anywhere else in the page
where the URL might not include that quote ID.
So that's a restriction which we now add to this component,
and that might be fine.
We can make this component more reusable
and independent from the URL if we not use, use params,
but instead expect to get that quote ID through props.
And that's simply an alternative,
and it simply depends
on how flexible you wanna make that component.
If it should be super flexible, you wanna use props.
If you're fine with restricting it
to be used in places where the URL
contains that ID only, that's fine as well.
If that restriction is okay,
and if you never used that component anywhere else,
then using use params is of course fine.
Here I'll go for the props solution.
And hence, when I sent the request,
I will add a second argument here
to this send request function and pass props,
quote ID as a value.
And now I of course expect to get the quote ID as a prop,
just as I expect to get a on added comment prop.
And hence, now we can go
to the comments JS file and add those props.
Here when I render the new comments form,
I wanna set the quote ID prop
and the on added comment prop.
The on added comment prop should point at a function,
which is executed when a comment was added.
The quote ID prop should forward the, well, quote ID.
Now, let's start with the quote ID.
For that in this comments component,
I can use use params, and here, that should be fine
because I know that I will always only use this component
in a place where the URL contains my parameter.
And then here I get the params by calling use params.
Of course, you need to import use params as well.
And then we can pass the quote ID,
simply by accessing params.quote ID, like this.
Now, for on added comment, we can add a new function,
the added comment handler function,
and I'll pass a pointer at this function
as a value for this prop.
Now we just need to add more logic
to this comments function.
To be precise, I wanna add logic for fetching my comments,
fetching the comments for a given quote ID to be precise.
Now, to fetch the comments for a specific quote ID,
we again can use the HTTP hook
and a function provided in the API file.
So I'll import use HTTP from going up, going up, hooks,
use HTTP, and I'll import a function from going up,
going up, lib API.
And the function which I wanna use here is get all comments.
Now, as we did it many times before,
we can call our custom hook and pass a pointer
at the request function, it should eventually execute to it.
And then simply extract some data here.
I get my send request function
and my status and the data, which are my loaded comments.
And we could also get the error to add error handling.
But since this is already becoming a bit more complex here,
I'll focus on the core functionality
and on working with that data and sending that request.
So these are the data pieces
which I extract from the return value of my custom hook.
Now, I wanna send a request to fetch my comments
whenever this component loaded or changed.
Hence we can again use, use effect, and register.
And effect here.
And the effect function
should send a request to load our comments.
So I wanna call send request here.
Now, this get all comments function needs to know
for which quote ID comments should be fetched.
So we need to pass that data to that send request function.
Now, we get the quote ID from the params,
and hence we could use params.quote ID here,
but then we would need to add params as a whole
to our dependencies here.
I wanna avoid this to avoid
unnecessary re-executions off this effect.
And hence I'll use object de-structuring here
to get the quote ID,
and then just pass quote ID here
and pass quote ID as a dependency.
Send request now, also is a dependency
because we're using this here in this effect.
And with that, we will be sending that request.
So now to handle the fetch comments and the status,
we can start by checking the current status,
and check if the status is equal
to pending here in this comments component,
in which case I wanna show a loading spinner
but I don't wanna return a loading spinner.
Instead, I wanna show a loading spinner as part
of the overall JSX content, which has returned down there.
Because I actually don't wanna remove the form,
for example, or remove this add a comment button,
just because we're now waiting for comments.
But I don't wanna show this paragraph
if we're loading comments.
Instead, I wanna show a loading spinner.
And if we got comments later,
then I wanna show my comments list here.
And therefore I'll add a little variable here, comments,
which initially has no value, which I'll assign a value to.
And you know that you can store JSX and comments as well.
In the end, JSX is just a regular value
in your JavaScript code.
So we can store a div year in this comments variable,
give it a class name of centered
and add a loading spinner here in this div.
And of course you need to therefore
import this loading spinner component.
Now we've got this comments variable set here.
We'll use it soon.
If we're not in pending status,
I wanna check if the status is equal to completed.
So we're done fetching comments,
and we do have loaded comments.
So we do have data.
Then I wanna set my comments equal to comments list.
And that's a component which I have to import here.
Comments list from./comments list here.
It's simply another predefined component
I provided to you earlier in this course,
at the beginning of this course
as part of the starting project, to be precise.
That's now the component I wanna output here,
if we do have comments.
And this component wants a comments prop,
to which I'll pass my loaded comments.
Now, maybe we also don't have any comments yet.
For this I'll check if the status is completed,
and we don't have any loaded comments or loaded comments
length is equal to zero.
And therefore up here, by the way,
I should also check if we have loaded comments
and loaded comments length is greater than zero.
That's how this check should look like.
Here, we're then checking if we don't have any comments.
And in this case, comments will be set equal to a paragraph,
which I'll give a class of centered where I say
no comments were added yet like this.
And now with div we got different values
in this comments variable,
and we can now use this comments variable down there,
just like this.
If we now save this, if I reload,
you'll see a loading spinner briefly down there
whilst it's fetching comments, and then it's done.
Now, if I add a comment,
we don't see that comment here yet, but if I reload,
it should be there because it was stored here
but it was stored under an ID undefined.
So I somehow did not use the quote ID correctly
in the comment form.
Let's see why that's not working.
I am passing my quote ID to the new comment form,
this quote ID prop.
With params quote ID, we could also just use quote ID here
because I'm using object de-structuring on params up there.
But it looks like I'm not using this ID correctly
in the new comment form when I'm sending my request here.
I'm reaching out to props.quote ID.
And actually here, we should change that at comment function
the API fall a bit, and just expect data here,
and then access data.quote ID here and data.comment data,
or maybe name it request data.
And then access request data.quote ID,
and requested data.comment data.
And now in the new comment component,
when we sent that request, we should send one object here
which has a comment data field, because in this API file
we just worked on, we're extracting a comment data field,
and which then also has a quote ID field with the quote ID.
So here we should also add a quote ID field
and store the quote ID in there.
That's a little change we need to make
on this API function to ensure
that all the data is used correctly.
A little error I had in this function at the beginning.
But now with that,
if we reload and then try sending this again.
If we reload again, our comment is here,
and we see it's stored under the correct ID here.
Now, we're still not 100% there yet.
One change we should also make
is that in the comments component,
this added comment handler function here,
should be wrapped by use call back,
a hook we need to import from react.
We should wrap this function with it,
and provide an empty dependencies array here
because added comment handler is passed
to the new comment form through the on added comment prop.
And there we used that prop as a dependency for an effect.
If we don't use use callback, this function
which we use here in the end will be recreated
whenever the parent component re-renders.
And that could create an infinite loop here
which we wanna avoid.
So wrapping this with use callback is important.
I did introduce use callback
and why we use it early in the course.
It simply ensures that this function is not recreated
all the time when this component is reevaluated,
and that avoids unnecessary re-render cycles
and infinite loops.
And I got another thing related
to this added comment handler function.
Of course we wanna add some logic here.
Whenever a comment was added,
the comments should be updated here.
And for this, we could send a new request.
So we can call, send request again here,
and again, use our quote ID,
and therefore add send request
and quote ID as dependencies for this use callback hook.
So that this function wrap by use callback
would be recreated if the send request function changes
or if the quote ID changes.
And with all of that,
if I now save that and I add another comment here,
we see that it's loaded automatically down there.
And now that's looking good.
And with that,
we added all this data fetching functionality as well,
which was another good practice
of all these core mechanisms,
which we learned about earlier in the course already,
sending HTTP requests and so on.
And with that we've finished this demo application.
Now we're able to add quotes here, like this.
We're able to view our quotes,
to view the comments for quotes,
and leave new comments like we did it before.
We added this sorting functionality with query params,
and we simply worked with react router.
And you now know how you can give the user the illusion
of a multi-page app in a single page app.
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.