Lesson 10
React Router and Retrieving Messages - Full Stack Web Dev Bootcamp Day 5 (2024-07-08)
Source Code: https://github.com/nbktechworld/full-stack-web-dev-2/tree/1781f79c9ae0d82e30c2bcc99c28763658c3dc7e
This lecture shows how to do client-side transitions with React Router.
Then it shows how to load messages from a backend and how to post a new comment using the same fake server.
Video Transcript
Okay, let's go continue, so I'm going to do two main things.
We have to learn how to do routing, we react router, and then we will do the messages page.
So this is what we're going to do, turn to the routing, popular solution written by
somebody else so we don't have to reinvent the wheel.
Okay, so what we've got to do is install that first with NPM.
So going back to my VS code, open the terminal, if you want to kill the server I can do that
and restart later NPM install, react-router-dom, based the command to zoom, just in case.
Okay, we got that in package.json now under dependencies, right?
I didn't talk about node modules, but basically the third-party code is installed in this
node-register-card-modules folder and you can also check that there's a react-router-dom
there somewhere, here, this one.
So the search code is available for you to produce.
Okay, so a lot of stuff there because our dependencies depend on other dependencies,
you know, this node.modules directory is infamous for that issue, but that's the way it is.
Okay, so we got to go to app.js and then we got to set up some routing here.
So what we're going to do is take this app and we're going to place, actually not here,
sorry, index, which is where it's actually using that app, opponent, and what we're going
to do is take this, just comment this out so I don't remember, oops, not like that, slash, slash.
And inside strict mode, we got to instantiate what's called the router provider component
like that, and that's from import router provider from react-router-dom.
Basically this is the component that's being charged of managing the routing and you got
to pass an attribute, what we call props, right, too.
And that's called the router itself and we got to build that router, let's call it router
and create a variable outside, let's call it router.
And this will come from function from create-browser-router, that's one of them.
And we got to import here, create-browser-router from react-router-dom, make sure it's within
the curly braces.
If you have multiple imports from the same module, separate a common curly brace here.
And then this function expects something, which is the routes definition.
I'm going to put in a separate file, since we had a half-time to explain right away,
I could write it here and then move to the file, but I would do it right away, okay?
I'm sorry about doing it fast.
So basically I'll create a variable called routes, and that's basically I would just
import routes from the file dot slash routes.js, by the way, when doing parts, it's implicitly
dot js, so we don't have to say it like that, and I usually put it at the top here.
Let's create the file here, routes dot js.
And this file here, because I did the import without curly braces, that means I have to
export or make the content available with export default, okay?
Default is the one without curly braces.
And then we're going to export default array, okay?
So we're going to create a variable here, routes, an array, and export default that.
Of course, I could have done it directly here, but I want to have that intermediate.
I think it's better for IntelliSense, IntelliSense is when you type something, it's auto suggest
something and knows what's inside, so I think having it this way works better.
Anyway, so here is an array of what we call route definitions, which is basically every
page we have in our app.
So because it's a single page application, we have to define what is virtually a page,
right?
We have this route, and if we go to slash messages, it should go to this component.
If I go to slash sign up, it should go to that component and render that, that kind of stuff.
So we have to define here.
So basically you can pass an object, an array of objects for all the routes, but the way
I'm going to do it is I'm going to have a master route, that's going to be the app.
And then within that app, I can nest many things because I want to have every single
page, I want to have a header and footer, that's the same thing.
But then I want to have the content, the main content always change depending on the path.
So that's why I'm going to do a nested thing.
So the path here for this is slash, which is the route, and the element or the component
is going to be that app from index.
So I'm going to take that from here, put it there, no slash slash.
Now because I need the import, right, because it doesn't know what that is, let me put this
down so you can see and close that.
Basically I'm going to take this cut from index, move to routes, so it recognizes it.
And then yeah, so that way I can show the app as one of the main routes.
So what is going to happen now is it's going to load this app as the main thing.
So it should look like almost the same, but let me see, we got that, we got that.
Now we need what's called the outlet, so I'm going to go to app, let's see app.js.
We got the children, we got to do to the main content, we got index here, let me see.
This part, so for that part I'm going to use, let's call it an outlet.
I'm not going to do index, do outlet.
And this outlet will come from React Router DOM, so outlet from React.
What is outlet?
Well it's basically a placeholder, you want something to go in there depending on the
path.
We're going to see it more later.
Okay, let me see if everything is okay by testing.
Going to Chrome, where's my Chrome?
Share.
Ah, let's refresh.
No not here.
Sorry.
I forget to restart my server, by the way, because I had installed main.vm.start.
There you go.
Which my Chrome is, there you go, refresh.
All right, now as you can see, it's pretty much nothing is there, right, because it's
empty.
Now what we've got to do is define all the nested routes and then add the reusable headers.
So let me show you.
Basically what's going to do is we're going to use app as like the layout, and then whatever
we have outlet, that's basically the main content.
So I'm going to take from index, I'm going to go here and take the header, which is basically
the navigation.
I'm going to cut that, okay, because I want every page to have the same header.
If I cut that from index, scroll down here, and put it before outlet, save it.
You should see going back to Chrome, that I now see the header here, okay, see the header.
And then the outlet is going to be the thing in the middle, and then finally I'm going
to have the footer, and I'm going to go, I don't think there's a footer.
Let's make one.
But after the outlet, and out of footer, copyright, post, stack, web, dev, copy.
This is by the way HTML entity, which basically if you want to show the circle of the C, you
could use these codes.
Basically it's always ampersand, whatever the name and semicolon.
So if you want to show like last then, like this one in code, or greater than literally
that, you would say like LT, or GT, because otherwise if you write it like this, it might
think it's HTML notation, right, that's why you got to do that.
Anyway, we got the footer, maybe you can add a side footer class there and define.
By the way, this has a CSS, right, app.css.
So we can go here and add a class outside footer.
Add some padding, 16 pixels, background color, about, I'll do antique white, something like
that.
Okay.
You can see the footer is there.
Okay, now let's go to the outlet, because the outlet we want to show the actual index,
right?
Before I do that, I didn't tell you that usually when we have multiple components, usually what
people do is we separate them each into their own file.
So instead of having all together like this, we kind of right click here, let's kind of
organize this kind of a mess.
So I'm going to make a directory for pages, and I'm going to create in, I'm going to basically
copy, cut this code for index and right click pages, create index.js and paste it there.
And because this component needs to be accessed from another file, I have to do export default
before function.
That way when I do export the fault here and go back to where it's used, which is going
to be by the way index, not app.
I would do here, sorry, routes, routes, I would do import index from dot slash pages
slash index.
By the way, you might see the extension dot jsx instead of dot js, because it's using
jsx, which is basically what it looks like HTML.
If you're using TypeScript, you're going to see dot tsx.
Okay.
Anyway, that's why we usually don't type explicitly extensions here.
Okay, so let's, what we got to do here in this file is add what's called the children
of this app element.
And we got to define pretty much other routes that are nested.
Okay.
Let's see.
Basically going to copy the same pattern, object, element, index, like this.
By the way, if you want this particular one to be a path, it would do like, if it's hello
world, you want to go to this element.
But since this one is supposed to be the route, right, the route, the one, the first one we
show instead of saying that we say index true here.
So that way this is the first thing.
If you go to route, it will pick this one.
If you try to go somewhere else, it'll pick others.
Okay, let's save this, then go back to app, clean this up.
We got the outlet here, which will be substituted with the index here, which is children of
this app.
And we got the index, the index, we got to do the parts because complaining, not define,
remember.
So basically we got to do this same thing.
And because I'm doing index there, I probably want to copy this and do the part here, even
though it's going to work if I have an app, but I don't want every single page to have
the CSS for index, so I'm going to remove from app and just have it only for pages.
And I think that's all, if I scroll down and see any more errors, let's test it out.
Maybe we're going to find an error in Chrome.
Oh, we have an error, right?
Let's read.
Cannot find module.slashindex.css.
Okay, that's because I moved the file, the content definition for index is now under
pages, and there's no index.css there.
So one thing I could do is either change the path or move the file.
I think it's best we move the file, right?
More organized.
I move index.css to pages, so they are side by side there.
Let's see.
Anything else?
Spailey, save everything.
Still complaining?
Why?
Is it cached?
Let's go back here.
I'm going to do a global search for index.css.
See where it's used.
It's used here.
Oh, I see, I see, I see.
This is from React app.
They already had index, right?
And they're using it here.
I don't want that.
I'm going to remove it.
Okay, I removed it from that.
And probably I want to remove all these other stuff here and move to the global or to the
app.css because it's supposed to be the one applied to every single page.
So if you want these, you can take them and now put either app or global.
I think app is supposed to be the global one.
Maybe we can consolidate later.
So basically you can put it here.
I think it's going to override maybe some stuff.
This one, ours is going to override if you put before.
Anyway, it's just stuff from the default.
We don't really care about that.
I'll just leave it there for your reference.
That's it.
Going back and testing it out.
I guess you know more console errors.
It's working like that.
We have the header.
This is, remember, this is app, right?
The outer thing is app.
You can verify by going, so you got a div ID root.
This div here is the app component.
And we got the header and we got the footer.
And remember that outlet thing from React RouterDome?
That's actually what gets substituted here as the main content.
Because we specify that nested route under the children for app, right?
In the routes.js, I put index true for that index component.
So that's the slash here, the root.
So that way we can now start navigating and transitioning to different pages.
But to do that, we cannot just use the a tag.
Because the a tag will always cause a page load and it will download something completely
or new.
We have to use instead a React Router's link component because the link component does
the client side transition, which basically is just rebuilding, is just changing the path.
And because of that, it rebuilds the stuff according to the nested routes that we define.
It doesn't actually request a whole new page a new from the server.
So you got to be careful.
Don't use anchor tag.
Let's go back and fix the links.
So basically would, let's go back to index, right, pages index.
These links, which are supposed to be navigation, actually I want them to be, I could put them
in every single page.
Anyway, import curly brace link from React Router DOM like this.
And then every time you need to link something that's internal, for external, of course,
you got to use anchor tag, okay, by the way, clarify external links.
So another website is anchor tag link.
And then they use too, for some reason, they don't use href, it's kind of annoying.
You could build like an abstract component to always use ref and use the underlying React
Router DOM.
That's what I would do.
That's to avoid having to change the two.
It's basically like this.
And for the sign up here, usually want to do a slash sign up and not have HTML extension
because we're going to define this path like that.
So let's see, I see sign up here, you see it's at the bottom, it's saying slash sign
up.
So I click and it goes to slash sign up, see it changes the route.
Obviously, we don't have the page yet to find, but it's working.
It's a client side transition.
If you monitor the network, you see there's not going to be any new page load.
If you look at document doc, and you keep going back and forth, there's no network request
for a new page.
Anyway, let's add that page, by the way, good exercise.
So basically, let's create a file here on the pages, call it sign up.js.
I don't want to just copy this sign up.html here.
Let's put it at the top from the source directory, if you remember.
The source under the root, by the way, not the source under web client here, so this
is what it looks like.
Basically, to create a component, remember function, give it a name, start first, letter
capital I, sign up, parentheses, no props, no properties, no parameters there.
Return the template as JSX.
And because we want to make this available to another file to import, we got to do export
default.
Can I do export default later?
Yes, you can do this as well, by the way, you can do it like this, either way.
I always report React from React at the top in case they all complain.
I think it's already behind the scenes adding it, so it's not complaining, but usually it's
always necessary.
Okay, now what's the template?
Well, look at the page, sign up.html, under the body, we're going to take all of that.
Copy, oops, accept the, don't copy body itself, and then you paste it here, and we got to
look into the stuff that's not valid.
Oh, right now it's complaining, right, why?
JSX expressions will have one parent element.
It's because you have, you're returning more than one thing here, one thing, two, three.
So in JavaScript can only return one thing, so how can we group them together, there are
different ways, you can put them in an array, or you can put them in a div, like this, enclose
everybody in a div.
By the way, I fold these because I don't care what's inside right now.
Or you can use a fragment if you don't want to inject an extra div, you can do react.fragment,
and that one will not inject any extra div.
Some people like using the shortcut, which is basically empty.
It's the same thing, okay.
All right, so let's walk through what we need to change now, right, we got some problems.
First is class, right, class equals, we need to change that to class name, because it's
react, so I'm going to control D every single thing, class name, okay, the way I do is I
like what class equals, control D, or I think it's command D or Mac, all the way through
to select all of them.
And that fixes it.
Now it's complaining about inputs, because it's not closed.
So basically you got to go here and add the slash to every single input, slash before
the greater than this one, and that one, and that one.
So I may basically multi-select with a slash, kind of tedious.
This one, and that one, oh, by the way, if you want to comment, this is supposed to be
a comment in HTML, right, which is supposed to ignore the code.
If you want to comment JSX, you got to use the curly brace slash star to start, and then
star slash curly base to end.
If you press control slash, if you have a code, it does that.
Control slash, control slash, I don't know if a Mac is command slash.
If you're using Mac, let me know.
I forget.
Anyway, that's the comment.
OK, we got that page.
I don't think there's any more issues.
If so, we're going to fix them later.
So we got the template all done.
What we got to do is including the routes file, so source under web client routes.
Under the children of app, you're going to add a new object, comma, object, curly brace.
Elements is going to be what?
It's going to be a sign up instantiated like this, and a path is going to be slash sign
up.
That way, if a user goes to slash sign up, a React router will take this component and
show it in the outlet.
Make sure to import here, sign up from dot slash pages slash sign up.
And I think that should do it.
Let's try.
There you go.
Go back home.
Oh, this home is messed up.
Don't do it.
I'm going to change from the route directly.
Go to sign up.
It's here.
So go back, go forward.
Go back, go forward.
So that's the client side transitions.
It's basically manipulating the document to look like another page, but it's not really
another page.
OK, it's not loading a whole new document.
OK, let's react router.
Let's add the messages.
And if you recall, there's messages there.
Got to do the same approach again.
You know, the more you do the same thing, same pattern, you get used to it.
So you can start from anywhere you want.
You can create the page first, and then do the routes.
Or you can do route first, create a page.
Let's do route first now.
So what we would do here is add an object under the children of these definition elements.
Going to be messages that I'm going to call.
Path is going to be slash messages.
Then we got import messages from dot slash pages that we are going to create soon.
Like that.
It's going to complain, by the way, if we do it right now.
Save it.
Anyway, go to pages, create a new file, messages.js, export default.
Because we want to make this file component available.
Function messages versus letter capitalized.
No parameters yet.
Early brace, return a template.
At the top, we really add import react from react because we're using JSX.
And yeah, it's open here at the top, messages.html from the root slash source.
Go under body, copy everything, accept the script.
It's like that because it's multiple things.
Remember, we got to use.
Either add a div or add a fragment.
Fragment is just an empty tag like this.
And don't forget to close in a line like that.
My indentation is kind of off here.
There you go.
Save it.
And let's see.
We got to fix the link, right, to go there instead of typing manually.
Go to app, oh, not app, sorry, index.
Here's the link, line 39 index.
Instead of a, it's link.
Instead of href, it's true.
And here we say slash messages removed.html.
Don't forget the closing tags should be slash link.
Okay, let me fix the home links, by the way.
I think there's some home links to remain that from messages.
I'm going to change that to link to,
I don't need an index, just say slash, yeah, link.
Because it doesn't know what it is, you got import,
curly brace, link, from react, router, DOM.
That fixes that one.
If we're sign up, you can do the same here.
Basically the same thing, link.
Basically this should be in the header, right?
It's kind of annoying having it here.
I think it should be in the header for every page.
So you'd probably move that to the app.js.
So you don't have to write it multiple times
or have a single page.
You only write it once in app.js, react, router, DOM.
Node dash there, right?
Okay, go back to Chrome, go back home.
Oh, this home is messed up.
Sign up, this is not correct.
Why?
Because I put href, that's why it's messed up.
This one has to be two.
Two.
Okay, now it says home, slash, yeah.
Okay, messages, home, sign up.
Okay, you got to hear.
Some problems with console, let's fix it.
First one is four.
In React, we got to use HTML4.
And we got class, class name.
And we got the unsubmit because you got to copy the OS.
Okay, let's fix all of that.
Go back to messages, first class, right?
Class equals, got to be class name.
This label, when you have a four attribute for labels,
you got to use HTML4.
Why?
Because four is a reserve keyword in JavaScript
to do looping, a for loop, repetition.
Okay, and then finally, unsubmit for the form.
It doesn't work this way in React.
Remember, we got to pass a function definition.
So we would do curly brace, not the quotes,
and remove this call there.
Then you've got to define add message here.
Before the return, let me copy the messages.
Remember, there's a script for message jays.
You can go here and copy this.
But it's not the proper way to do it in React.
There you go, like that.
So that way, by the way, they ask right here,
capital S, on capital S, submit.
React doesn't like lowercase.
And when it's submit to form, I call the function here.
Let's see.
Refresh.
No errors in the console, great.
It's adding it, but there's no styling.
It should be a square box.
And that's because we got message HTML.
We got some styling here, line six.
So how do we do the styling, remember?
React, we will import the path to the CSS file.
Let's copy messages.css and place it
under web client pages under source.
And it's here, going back here or doing port,
quotes.slashmessages.css.
So that way, it's, by the way, I didn't explain
how it does the mechanism of CSS, right?
Let me show you.
Basically, what it does is it reads the file, CSS file,
and then it generates a style tags
and inject that in the head.
We can easily see that if we go to the elements tab
or inspector in Firefox, you can check the head.
And you will see right before the end,
all these style tags, that's actually, you see this one
is for the messages.css.
That's what happening.
So the JavaScript reads the CSS content
and then injects that as style tags before the end of head.
So you can see all of them there.
Yeah, it's CSS and JavaScript.
Whereas before we were doing link tags,
this one just dynamically creates these.
Anyway, that's the mechanism.
Now you can see it's their style there.
It's working the vanilla JavaScript way.
But we've got to convert to React.
How to convert to React?
Let's go.
OK.
So React, we don't want to be manipulating the document
directly because React is doing that for us.
Instead, we declare what we want to see.
We tell React what we want to keep track of,
what kind of value in the state.
OK, so let's first have some default messages.
How would I show it?
Well, you can maybe let's create an array here.
Call it messages or comments.
Let's each be an object.
Let's say ID is one and comment hello.
And add another one to comment test.
Basically, we represent each message
as an object with ID to give it a unique identifier.
And then a comment is basically what you're going to see.
And it's a list of things in an array.
And this is just dummy data for now, OK?
Because I want to tell you how we would show this in React.
So basically, what we can do is we
would go here in the template where we have the message list.
And we would go over these messages,
iterate for each of these elements.
I want to generate that div with the class message list
item in the text content, the content, comment.
But this is the programmatic way in React
to do declaratively.
So let's go.
Here, you're going to go, OK, I got messages.
If I want to iterate over an array
and generate new elements with the same number of elements,
I can use map, OK?
That's the JavaScript function.map.
And you pass a function.
And it's going to go over each element.
For each element, you call this function
with the argument here, being the element itself.
I'll call it message.
And we can return a div with the class name, message list
item.
This is the declarative way of what we did there
programmatically.
And then the text content is going to be message.comment.
Remember, message is an object.
It has, like this, a property comment.
So if you want to access an object, comment value,
say dot, comment, right?
Because comment belongs to this message object.
And then finish the div.
So that's the equivalent of this whole thing here
in a panning the child.
You see how it's much easier to see
than having to type all of this, just to do that.
Can just declare it and React will automatically
change the document.
There you go, like that.
Let me refresh, by the way.
See hello and test there.
We took a value from a variable, an array of objects.
And from those, for each of them,
we generated a new, completely new div
using the class name and the value from the variable.
Very powerful.
OK.
Now, how would we integrate this comment into that?
Well, we've got to use state.
So React knows what's going on.
If we don't use state, it won't know when we change messages,
just like we did for that other page.
Remember, we tried to change paragraph style.
And it wouldn't change, because React didn't know about it.
So React didn't re-render or update the document.
So you've got to do the same thing.
So here we're going to do what?
React.useState.
Here's my initial value, this array of two things.
That's the initial thing.
We're going to take that, extract the first element
into messages, the second into the function
to change messages that we call setMessages.
Notice by convention, we always call it set, whatever
this name for the first variable is.
Well, of course, you can change it to whatever you want,
but I think it's going to be confusing to understand.
So you always want to be descriptive of your variable
names.
OK, now whenever you need to add a new message,
you call setMessages, and you can pass the whole new list.
So what you would do here when you click Add Message,
instead of, OK, we would call setMessages.
But first, we've got to be careful.
When you call setMessages, it will wipe out
everything that's already there.
So what you want to do is you want to first copy
what already exists.
So if you want to copy the elements of the messages array,
you would do dot, dot, dot messages.
So that way, it would take the initial ones that already exists.
Now you can choose.
Do you want to put the new message in the top or the bottom?
If you want bottom, you would put it here.
If you want top, you want it here.
So I'm going to put it at the top, OK?
Now, what is this new message?
Well, for now, let's just add that's one, two, three, dummy.
And let's comment out all this stuff here.
We don't want that anymore.
I'm going to comment this out, too.
And obviously, I'm not faking what the user typed just yet,
because I want to show you that this is the mechanism
that we're going to use.
So whenever I click Comment, it's going to add dummy, OK?
Like that, like that, like that.
Right now, it's nothing, right?
Why?
Why do you think that's causing the, let's debug, OK?
Let's debug sources or debugger in Firefox.
Go to app, right?
Control P, app.
Not app, sorry, messages this time, .js.
It's either this or that.
We've got to check, OK?
Maybe it's, I think it might be the second, let me see.
And then we're going to go to the function here.
Oh, not that one.
Sorry, that one is the wrong one.
It's this one.
Yeah, there we go.
Now let's go here and put a break point.
Let's click Comment.
It's pause here.
OK, pause.
Control, back tick.
Let's investigate.
OK, what's in messages right now?
Look, dummy, dummy, dummy.
What is this?
Zero is the first position on the array.
Second index, one.
There's a string of a string, right?
But look at the other ones.
The other ones are objects.
So what mistake did I make?
I didn't make them objects with the comment property,
because that's what it's expecting to create their tips.
So with that, understood that, go back, fix it.
Here, we've got to change this.
You've got to be what?
Comment, object of the comment property and value like that.
So that's a way of debugging things, OK?
Investigate what's the data type it's expecting.
Down there in the map, right?
It's message.comment.
Right now, I had message like dummy.
So this would be like dummy here.
And it would take dummy and try to access comment out
of dummy, which doesn't exist.
So it gives us an error, OK?
So it got to be an object.
Going back here, remove the debugger.
If you want to play around, you could close it, refresh,
comment, dummy, dummy, dummy.
In a box.
Now, how do we get what the user typed?
That's the next question.
Well, we got to control this component.
When we control a component, do two things.
Add the value attribute and use a state to track that.
And then you add a non-change to change that
when you type any character.
Let's do it.
Go back here.
Whenever you have text area, we're
going to add a value.
Let's call it a new comment.
How about that?
And you need a non-change.
Now, this non-change would be a function.
OK, let's call it on comment change.
And then we've got to define these two things.
Let's go here to find the state.
Reacuse state.
Initially, it's empty, right, in the text area.
So empty two quotes like that, either double or single.
Doesn't matter.
But empty string.
And you can call that new comment,
comma, set new comment, like that.
The second thing is the function, right?
Function on comment change.
Now, we're going to need to access what was typed.
So we need to the event argument.
Because every time there's an event,
you get that object to access details about that event.
This case is when you change it whenever you type a character.
So when I type a character, I want
to update the value of new comment, which
is the value that should be appearing for the text area.
So I have to say set new comment with that new value.
But how do I access that?
Well, I've got to say event.target
to first grab the text area.
And then dot value to access what the user typed.
That way, every time I type a character,
it will set the new comment to whatever the user typed.
And with that, we have access to new comment,
what the user typed.
You can go here.
Instead of saying dummy, you can just say new comment.
I usually like to move all my state stuff out to the top,
by the way.
So I like to put it here.
Like that.
You can see this is coming from there.
Let's try.
Brush.
See, every time I type a, whatever, it's changing.
If I didn't set this up correctly,
it would probably be something that you couldn't change.
But a comment is there.
See?
Yay.
Want to investigate that more?
DevTools is your friend.
Let's go here to Messages.
And you can click.
Let's investigate on comment change
if you didn't understand.
When I type a character, it's going to call this.
Put a break point here.
Let's type a character, v.
You see it's triggering this function?
Let's look at event.
Event has all these things that informs you what just happened.
And it tells you what's the type of event, change.
OK, who's the target?
The target is who triggered change, this text area.
So if I access target, event.target, what do I got?
I got all these things.
And I have one called value.
If I click, is what was typed.
That's how you figure out which property to use.
OK, so it's pretty much going to set the new comment with that.
Right now, what's new comment?
Let's look.
It's probably going to say on the find again.
Let's see.
It's not.
OK, there you go.
It's whatever without the v, right?
That's the previous state.
And then it's going to be overwritten.
And now there's a v there.
And this value will have v if you had a break point in the render.
But anyway, get the point.
And that's how we do it.
Now you notice we didn't clear this when you click comment.
How do we fix that?
What's the function that allows us to change the value of the text area?
Remember text area here?
The value is new comment.
And that's from the state.
And there's a function that we can call.
So here we would say set new comment to empty string.
That way, when I comment, it will clear.
By the way, I don't need this anymore.
Save it.
Try it again.
Comment cleared.
Type again, comment, clear the text area.
OK.
Great.
If you have any questions, let me know.
Kind of almost out of time, I don't think
can do much explanation about the fetching data
for an external server.
But I can try to go fast, but you'll probably be left
not understanding what's going on.
But let's see.
Let me see.
So there's this place here that I can get some dummy data,
especially a fake back end.
Let me print for you.
That's the place.
And we can use this dummy data.
I think it's on 100.
If you want a limit, you can add, I think,
question mark underscore limit, let's say, 3.
So we only got 3.
Basically, it's a server, right?
Somewhere else, a back end, that returns posts
that we can think of them being stored in a database,
so they persist.
And this, obviously, we're going to write this later,
but we can leverage this.
Because if you notice, every time we refresh,
we lose the data, because it's not persisted.
We need to actually call a back end
and start the information.
So how would I retrieve information from this server?
Let's work on that.
So basically, if you need to set anything initially in React,
we're going to learn a new hook called use effect.
So basically, OK, the React component renders,
it's on the screen.
What we got to do is make a request to this server,
hey, I want the post information.
You've got to wait a little bit, so it's
going to return to you a promise.
Hey, I promised to give you back the post,
but you've got to wait a little bit until I get them.
So we've got to wait, and then when you get them, OK,
here are the post information.
What we do, well, we're going to take that
and set new messages with those posts.
But how do we do that in React?
Well, we do it using use effect, meaning
after the first render, we do all that operation only once.
OK, so we're going to go here.
Let me first show you how we can do with the dummy data
initially.
So I'm going to take this dummy data
and just put an empty string initially to simulate.
We don't have anything right now, right?
So you're not going to see anything.
So we're going to react our use effect,
and the second argument has to be empty string.
Otherwise, this function gets called after every render.
That is, when you change state, render, call use effect.
Change state, render, call use effect.
So that's not good.
We only do that once.
So we add this what's called array of dependencies,
empty array here.
So we only execute this once after the first render.
So I want to set messages to these values.
You're not going to notice it right away because it's so fast.
So I'm going to use a timeout to delay that, OK?
So I'm going to put a delay there.
Two seconds.
Let's see.
Where's my Chrome?
Refresh, nothing, nothing.
There you go.
After two seconds, it's set the new message, OK?
That's similar.
Now can we do that with the actual back end?
Yes.
How do we do that?
Well, let's remove the timeout, remove this, set messages,
leave it hanging here, remove the timeout.
So OK, component renders, call the use effect function.
By the way, I use the error function, if you notice.
It's basically going to use function too.
Doesn't matter.
So we're going to call fetch.
Fetch is a function we can use to retrieve information
from another server.
That is, we make an HTTP request.
By default, get, method get, so we're
going to do a get request to that place, slash post.
And then this thing returned was called a promise.
So remember, you've got to wait.
Hey, I've got to give the information.
Please wait a little bit.
So in order to handle that and only do something after waiting,
you've got to do what's called dot then.
And it has a function that will be called when this is ready,
when this promise is fulfilled.
Otherwise, it doesn't work.
You've got to wait for this.
And it's going to call this function.
Now, this function gives you back.
You can access the response.
When you make a request, you get a response object.
And you get information about, OK, this is the response.
This is whatever, whatever.
And then you've got the body of the response that has the data.
To extract the information from the body,
you're going to do a return response.json call like this.
It's going to extract the body, parse that in the JSON format,
which basically going to turn into an array of objects
in JavaScript.
Now, this also returns a promise.
So you've got to wait.
Hey, wait for me to do this operation.
So you've got to do another then.
It's called a chain of thens.
But it's outside.
So you've got to do dot then.
Because this whole thing here will return a promise.
And in order to wait and then do something
after receiving the stuff, you've
got to pass another function here to the then.
And this will be the actual posts, OK?
And once you've got that, you can just call set messages
with those posts.
Obviously, I think they use a different, let me see if it is,
different.
Yeah, they use a different property, not comment.
If you see here, they use title or body.
We can just use title for now if you want to.
So we're going to have to change a little bit of things here.
So for every post, I want to change and map to a new one.
Well, I can leave it like this or change my thing here
to instead of message.com is title that works too.
But let me do that first, OK?
I change this to top title.
And then I'll show you the mapping
to change the property name.
Anyway, see Refresh, all that stuff.
It's 100 posts.
It's happening so fast, right?
Initially, empty array, make the request, get a response,
extract the body JSON, and then set messages.
And then it re-renders the components
because the state would change, react,
reacts to the change.
And it's all there.
OK, I hope that makes sense.
Let's fix.
I want to revert this back to comment, by the way.
And let me show you the way you can change the properties.
So basically, here I would do dot map and pass our error
function, by the way.
In an implicit return, I can do like this.
Just copy the properties from the object post.
And you add comment is basically post.title.
This way, you just copy whatever exists and add a comment,
which is basically duplicate of title.
You could, of course, create a new object
and remove all the other properties.
That's fine, too.
So this is the implicit way of error function.
I honestly don't like this, because I like debugging break
points, and I find it hard to understand
what's going on when I'm doing stuff.
So I like to always explicitly put a curly brace return
like this.
By the way, the parenthesis is not necessary.
It's just sometimes, if you do weird things,
it might mess you up.
But let's debug that.
By the way, I wanted to change the limit here, add a limit,
because too many messages.
Question mark limit underscore limit equals 3.
That way, it's easier for us to understand.
There you go, just 3.
Let's debug, so you can see what's going on now.
Where is it?
I want to put the debugger here, OK?
After the first then, and then put a debugger in maybe
after this.
Maybe I'll put in the render here before the return,
so you can see what the messages is.
OK, so refresh.
It's paused in the first render.
And you can see messages is empty array, right?
Continue.
Second render, what's in messages?
Still empty.
Let me go up, OK?
And then you can keep going.
OK, message is still empty, but it
rendered the things, the body, right?
And then go.
Next one, still message.
I can keep going.
Now, it's three array, three elements in array.
And you can see them, what do they look like?
I have title, I have body, and I added comment, right?
That's what I did here.
It's kind of redundant, right?
I did the same thing as titles.
So you could have replaced it to create a new object,
but whatever.
Later on, we're going to create our own back end,
so this won't matter at all.
Anyway, that's it.
And yeah, we don't have a way to do the back end of the post,
but it's basically the same approach.
We're going to call Fatch and just do method post.
Let me show you here.
Basically, when you add a new message, when you click,
you type something, add comment.
We have to call the server first to see if they
let us add a new message.
So basically here, you would say Fatch.
And that same place that we use also has a method called
post.
Here, you have to have a second argument, method post.
And you need the body.
In this case, what do you want to send to them
to create a new post?
OK, you've got a JSON string if I actually this thing.
But they're going to use title, right?
Post has title, whatever.
I don't even know if this would work in that fake back end.
Let's try.
Let's try.
And put the message like that.
And new message.
What am I doing here?
Basically, I take this object and I turn it into a string
by calling JSON stringify.
Basically, it takes this and converts to string, OK?
Usually, pass headers to this HTTP request saying, hey,
we're sending JSON.
So the header is called content type, JSON like this.
And this returns a promise.
So we've got to do that then.
And then we'll give back a response.
Obviously, you've got to check if no problems,
response.OK is the property you want to check.
But I'm going to assume happy path.
So you can exercise for you to check if it's a good response.
Otherwise, response JSON to extract the body
and then do adopt then outside.
And finally, usually, when you create a resource,
it gives you back the same thing that you created,
including an ID identifier property.
So you're going to get the created post here that I
can call it whatever, by the way, this variable names.
And then I'm going to finally set messages
with that created new post instead of this new message
because new message doesn't have the ID.
Created post is the one that has.
And that's pretty much how you do submission to the server.
Let's test it out.
I don't even know if that server accepts that format.
We can test in the DevTools.
By the way, this warning here happens when you do mapping
and add a key.
Let me backtrack.
When you do dot map in JSX, it always wants you to add a key here.
So you add a key with something unique, maybe message.id
is something unique.
Anyway, going back, refresh should get rid of that.
OK, you've got a break point here.
I don't want it.
Oh, here they go.
I don't want that one.
Refresh.
I want a break point in, let me remove them.
In the fetch here to add message,
I want to show you that it creates the post.
A, B, C. Let's see what we got.
Oh, it did create it.
You can see network tab.
Let's go fetch XHR.
This is the method post headers.
You see this one?
This is the request we did.
If you click network, go to the filter XHR posts.
You see we did a post request to that.
And here are our headers.
Remember we did a content type.
It's here.
And we had the body, which is the payload.
This is the JSON string 5 version.
Comment ABC and the response.
They actually created it with the ID.
You see the ID there?
So it's a fake backend.
Obviously, it's not a real thing,
but at least it recognizes that.
And then finally, go on and add here.
Assume it's a fake backend.
It's real, and they accepted our comment.
And out of here, I tried another one.
Same thing, OK?
Call the server.
Hey, I want to add in your comment.
They would do all the checks, right?
You would have to be logged in.
Are you authorized to create a comment?
Obviously, we don't have those things,
but that's what would typically do.
They would validate your comment first.
Hey, is this a valid comment?
And start in the database eventually.
Obviously, they would remove anybody
trying to inject scripts.
We're using HTML tag script for access.
It's called the XSS for security problem.
And then, yeah, they would give a response.
And they would error out.
If they give an error, here you have to say an error message.
Basically, you create useState and put a string in the state
that's initially null or empty.
And if you have a problem, set that to something.
And then put in your JSX.
If that is defined, show a div with that error message.
And if not, it just gives you back
the comment in the response body with the ID.
And it can use the ID as the unique identifier
to understand, hey, it was starting the database.
So when I refresh, I would see it again.
Obviously, I don't think these two will be there
because it's a fake backend.
So we only see the persisted default ones.
When we do have our own backend that persists the actual data,
we will see them not go away when we refresh.
OK?
Anyway, I think that's the end of this lecture.
Thank you for being here up till now.
No comments yet (loading...)
No comments yet (loading...)
Did you like the lesson? 😆👍
Consider a donation to support our work: