Lesson 16
React Native Navigation and Mobile Messages - Bootcamp Day 16 (2024-09-26)
Source Code: https://github.com/nbktechworld/full-stack-web-dev-3/tree/185a563987e865eb7e6d0d4c55bfe4e769829dbc
The lecture continues building the mobile application using the React Native framework and the JavaScript programming language.
You learn how to navigate with a stack navigator from the react navigation library.
The lecture also goes over implementing the message board for the mobile application, involving concepts such using React hooks, making HTTP requests, debugging with DevTools, etc.
Video Transcript
Let's talk about navigation for the mobile application.
So we want to be able to change screens and one of the ways we can do that is with this
library called BIAC navigation.
So first we're going to install that and then we're going to learn how to use it to
make a stack navigator.
So here's the source code, I got two terminal windows open, one for the back end and another
one here that we're going to use for the mobile.
So I'm going to CD to mobile and we're going to install some things first.
So npm install at react-navigation, sorry, at react navigation separated by dash slash
na2.
And then after that we're going to do npx, expo, space install, space react, native dash
dash screens, and then space react dash native dash safe dash area dash context.
And then finally npm install at react dash navigation slash native dash stack.
Okay for check package JSON we should have all those packages.
So first we installed react-navigation-native, then we installed some native screens and
safe area context, and finally we installed the actual native stack which is for the implementation
of the stack navigator that we're going to use.
Let's go to app.js in the mobile directory, let me hide this for now.
So here we're going to go all the way to the top, we're going to make something ports.
See here, got my, okay so we're going to need navigation container, so we port that from
at react-navigation slash native, and then we're going to go here, let's first extract
this stuff from app outside, it's kind of, let's make a new component for that, so we're
going to make a function here, let's call it the image gallery how about that, then we're
going to return something, and that's something we're going to take this whole thing here
and paste it there.
So I'm moving the implementation to another component, and then we got to take all this
stuff before the return and move it there as well, and then here we can actually use
that component if we use it just like an HTML element, like this, and you can self close
like that.
You can even go a step further and move that file to a separate, move the component to a
separate file, which is usually what people do, so let me make a new folder here, I'm
going to call it screens, and I'm going to call image gallery.js, then I'm going to take
the definition for that function, cut, go to image gallery.js, paste, I'm going to fix
my notation here, because we want to be able to import this and use this component from
outside, we got to export default here, before the function definition, and then we're also
going to have to make some imports at the top, because it doesn't recognize a few other
things, so you can just copy from app, and just paste there and remove what you don't
need, like this one style sheet, might need style sheet, I don't know, I think it's defined
here, but we don't use it, and then we're going to import from app.js, the image gallery
from quotes.slashscreen slash image gallery, I don't need to say.js, it's optional, and
then save it, let's test it to see if it's still working, so remember we're going to
go npm start, if you don't already have it running in the mobile directory, make sure
that your smartphone has the app expo installed, I'm going to use my camera app to scan this
QR code here, then it's going to open my expo app, and I should be able to see it, let me
just show you, here it is, seems to be working like usual, I still got the each child in
the list would have unique, that's a problem we could fix, let me show you how, that's
usually when you do map in a JSX, where we do here, and images dot map, if this is inside
the definition for image gallery return value, I had the key in the image, but when I introduced
the view, I didn't, I forget to move this key to the view, so you move that, that way that
warning will go away, anyway, things are working like usual, so now let's do the navigation
thing going back, so we're going to enclose the image gallery in the app component, in
a navigation container, make sure the closing tag is after image gallery, and then for this
we need to add a navigator, stack navigator here, and then to be able to use stack, we
have to create that, so we're going to create a variable here, and that variable will be
the return value of a function called create native stack navigator, which comes from
the add to react dash navigation slash native dash stack, so when I do enter and call it as a
function with parentheses, it automatically imported for me, thanks to VS codes, auto import
feature, once I got that, I call it stack, but you could call it anything else, I create a
navigator here, and then finally we can introduce all of our screens, so basically you have the
navigation container, and then you have your kind of navigator, and then finally you have all the
definitions for the screens, so we can use stack dot screen component to create your screens in
itself closing, now to the screen you can give it a name, for example, let's call it image
gallery, and then the component that you want to show for this particular screen, it's going to be
image gallery, you don't have to define it like we did here, so we can eliminate that.
Okay, now let's make a home screen, so stack dot screen, I'll call it home, and the component
will be the home component that I'll create, so I'm going to go up here, import home from dot
slash screens slash home that I create, go to screens, new file, the home.js, let's make a
function, function home, that will be the component, so we're going to return the template,
I'll just add a view with the text,
to be able to use those we got imported the top with the curly brace, the view and text
separated by a comma from quotes react-native package,
now to be able to have this function be used from another file, we got to export defaults,
you could do it here, like we did before, or if you like, some people like doing after the end
like this, that's also another way, we're going to save that, going back to app, save that,
now I'm going to go and reload my app here to see what happens, sometimes when introduced screens
like this, the order doesn't quite appear in the way it's supposed to be, because usually the first
component defined here in the list will be the one to show at first, if you don't have any
particular definition for the initial route name, so I'm going to shake my phone and press
reload, and I should be able to see welcome home, that's the first screen, the default one,
as you can see here we got the text, welcome home, and at the top this navigator stack,
it adds the kind of status bar at the top of menu bar, with the title which corresponds to the name
by default, okay let's go back, so let's add a wave for us to go from one screen to another,
so we're going to go to the home screen, I want to be able to go to the image gallery,
so I'm going to add a button here, so add a button with title image gallery,
and then on press will be on image gallery press, a function that I'll define,
let's go before return, define the function on image gallery press, and we're going to do here
the navigation, so by default the component that is passed to the stacked screen here,
this one, it will receive as props an object that you can use a function to call to navigate,
so every component actually can receive props, so we can put a props parameter there for the
component function, and then from there we can use a function to navigate,
okay, so let's go, so when you press the button image gallery, I'm going to call props.navigation.navigate
function, now you got to pass the name of the screen you want to go to, and the name has to be the
same as the one you specified here in the definition for stack dot screen, this one is just image
gallery, so make sure you pay attention to the casing and the characters, each character,
it's going to complain because button is not defined, so you got to include
button here in the import, that's tested,
as you can see there's a button I'll press and it goes to image gallery,
if you notice that the title of the page is the name of the
component, definition of this screen, you can change that by passing options
property to the screen component, and on the top left you're going to see a back button that goes
to the previous screen, if you press that it kind of pops that screen, imagine a pile of plates,
this is called a stack navigator, so as you go through the navigation, it stacks on top,
and if you want to go back it just removes the top one, and you can see the thing below under it,
okay,
let me show you those
props that I talked about, so you can put options here to the image, sorry not this one,
so let's go back to app, definition of stack screen for image gallery, you can pass the property
options that value is an object with the property title, that you can change here to
something else for example, just say gallery, and if you do that and you navigate to gallery,
you'll see at the top it would just show gallery instead of image gallery,
okay, so let's go back,
now that we have this, let's add a new screen to show the message board, like we're doing the
web client, so I'm going to add a new screen, I'll call it messages.js, let's export default
function, messages, we're going to take props, name we're going to return,
let's add a view, I probably want to use a scroll view because we want to be able to scroll,
so we're going to import scroll view from react native,
I'm just going to add some tests here,
so we can have placeholder for now,
and then we're going to go to home, add a new link, which is just a button,
so you can repeat the same process, add a button, let's call it messages, on press,
you can either define the function outside, you can also define it here, if you want to do it here,
one way is just passing the function, like this, you can just call props.navigation.navigate,
and then give it a name, so this one would go to messages, right, we got to define it here,
if you want to use arrow function, that's okay, you might see this a lot,
it's not a way of defining a function, if you remove the keyword function,
and to the right-hand side of parenthesis, add an equal sign,
and then the greater than, you can also be in implicit return, meaning you don't have to
have the curly grace, you can do that as well, and then it would look like this,
let's define that screen, go back to app, app component, I'm going to add a new stack.screen
definition, with the name being messages, has to match what we use for the argument to navigate,
the component would be messages, and if I press enter, it will auto import, you can see here,
and if you want to options, you can pass title to be different, like board, something like that,
now let's test it out,
I went back home, and if it doesn't show to you right away, you can always shake your phone and
reload, and it should bring it to a fresh state, press messages, I see messages there,
so we can start working on that new page now that we see it's actually working,
and you can see board is up there, because I specify the options.title,
okay, something that would be good for us to do is every time I'm working on a feature,
I don't want to be able to, I don't want to be clicking every time I reload, I have to click
messages or something, I want to always see messages by default, so one way you can do that
is by specifying an option, a property to the navigator,
locate the stack to navigator, add initial route name, and then you can pass messages,
that way it's always going to be by default messages that will appear,
and you can change it back later to home,
okay, so if you do it again, you should be able to always see, if you really
reload, you'll see always messages by default, which is what we're going to work on next.
Okay, back to messages here, let's start working on, if you recall, we have a backend server
that has some endpoints to retrieve some messages, so you can call like the front end,
if you recall from the front end, web client, you can go to source,
and if you look at the messages component that we wrote there, we had this call here to fetch
from localhost port 3001 slash messages, so overall the approach will be almost the same
because it's React, so since we learned React for the web, it's pretty much the same
for the native, we're going to use the same fetch, we're going to use the same use state,
the same use effect, and so on, so you get pretty much copy and paste and just tweak a little things,
anyway, let's go back to messages, so when this component is rendered, when the user comes into
the messages screen, we want to execute set of instructions to retrieve the messages for
the message board that we will show, so we use that with react use effect,
and you pass a function as the argument, and the second argument to the function
will be an empty array of dependencies, because we only want this function to be executed once
after the first render, if you didn't have the second argument empty array, it will always
execute the function pass to use effect after every render, when does a react component render,
when the props or the state changes, okay, and then we're going to fetch
from hp colon slash slash localhost 3001 slash messages, now I'm going to take this
base URL here and extract it to a variable that I'll call here outside, I'll call it API,
or call API URL about that, and then I'm going to interpolate here with the dollar
curly grace API URL, so the value of API URL variable will be substituted here,
in order to do that, the quotes have to be back ticks,
and then this will return a promise with a response, we got to handle that,
then you pass a function there with the response, and you follow the same thing we did from n,
and the errors, if response not okay, let's assume the happy path, you're going to return
the response.json function call, so that it extracts from the body of the response,
the data, and turns that into an array of objects, and that return returns a promise,
so we got to handle that as an outside dot then here,
and then you pass a function, and that function will hold the array of images,
let's call an image list, sorry, not image message, it's going to be pretty much the
same code as the front end, and then we need to find a way to store all that data,
we can store it in the state, so we're going to go outside and do react use state,
initially it's an empty array, and then you can just structure that because your state returns
two things in an array, the first element is the thing you want to access, the value,
let's call it messages, and the second is a function that we can call to change that value,
set messages, and then here we can say set messages in the handler for the response json there,
with the message list, that way we start what we receive from the server in this variable messages
here, okay, once we got that we can display it here, so you can pretty much map over the messages,
you can say let's go after the text, curly brace, messages, array, dot map, and then pass a function
with each element being iterated over, and we return a template, we can do like a view
wrapper here, that we can style, and then you add the text with the message dot,
I think it was body, right, we can verify later, and if you want to add some style to
differentiate them, you can go here and define maybe you want a background color, I like this one
antique white, and then some border about, I think water widths, one border color, luck,
luck, let's add some padding, 16, and then some margin, bottom, about 16, too,
okay, let's do the imports because we didn't import react at the top,
and one thing we're going to run into trouble is with the fetch call to the server, because right
now the app is running on the phone, and the phone cannot access the backhand API, so to get around
there we've got to do some tunneling, let me show you how, so we're going to go back to the server
here, package JSON, I'm going to add a new command here, I'll call it tunnel, and this we'll call a
package that we need to install called local tunnel, we'll just call lt, and then we're going to pass
the port that's used the way to backhand, I think if you recall from the backhand that's 3001, right,
so let's go back here, I'm going to say lt dash dash port 3001, and every time you, basically what
happens is you're going to run the server, backhand server, and then you're going to run in a separate
tab this tunneling thing, and this tunneling thing will give you a new address for your server that
you can use from the mobile app, now every time you run, you kill the server, it's going to kill
your tunnel, so you've got to restart that, and then when you restart, it gives you a new address,
so that's kind of annoying, so if you want to have a fixed one every time, you can specify dash
dash subdomain here, for example, full dash stack dash web dash dev, and let me add a comment here,
now we need to install this package because we don't have dependencies, so this is just for
development, by the way, so I'm going to install under dev dependencies, so going to the terminal
for the server, I'm going to kill it, do npm install local tunnel, and I forgot dash dash save dev,
there you go, so it doesn't go to dependencies, but dev dependencies, you can see now it's here,
now we can use the command npm run tunnel, so first you're going to run npm run dev to run the
localhost 3001, and I'm going to open a new terminal window, and I'm going to cd to the server
and npm run tunnel, now it's going to give me this URL that I can copy,
and I can use from my messages instead of this api URL being this, because it's not going to work,
I can use this one instead, so I'm going to leave this other one as reference,
in an actual production, you would have your domain, right, api.yourdomain.com,
so it would work without having to do this, anyway that should take care of the problem of local tunneling,
let's test it out, we got api URL, let's see here,
reload the app,
so I don't see anything, so we can, I cannot show you how to debug again,
see there's nothing going on, you can see here there's some promise,
unhandled promise rejection and expected character, so we can investigate this,
let's dismiss, I'm going to share,
okay so we're not handling errors, so in this fetch call,
something's going wrong, so we can add a .catch block here with the function that will receive the
error, and then we can show the error on the screen if you want, let me add here,
you see here after messages, I'll add,
let's call it messages error, if that variable is defined, I'm going to short circle to double
100%, show a text that says fail to retrieve messages, colon and then gonna dollar,
sorry no dollar, curly brace with messages error to substitute the value there,
and if I want to add a style with some color red to make it more prominent,
then we're going to go up here and define within the function messages,
react use state, gonna give it, let's give it a no, and we're gonna call it messages error, set
messages error to keep track of that, so every time when we catch something here,
we're gonna set messages error with error dot message,
and if you do that we should be able to see that error message in red color,
fail to retrieve messages is some parts error,
now let's investigate this error,
why is it happening, I'll show you how to debug with the DevTools,
so here in the terminal for the front end, the mobile client, mobile development server,
this one where you have the QR code, you can press a J, let me see, I'll show you it,
where it shows J to open debugger, another way is you can use your phone to shake it and press
open debugger, so I'm going to press J, sometimes it's acts glitchy, so for example,
and the first time it was on a Mac, you had to grant it permission, I think it's to the terminal
or something to open the DevTools, so there's some stuff like that,
so here's the DevTools,
let me,
so just like the web where we debug the browser developer tools, we do the same with react native,
it opens like a Chrome DevTools here, and you can click sources,
and you can actually go to the control P or command PO Mac to go to the desired component file message.js,
and I want to put a breakpoint in the line 13 here, which is where when we handle
and the catch block, too, I think the problem is happening here in this response, Jason,
so I want to put a breakpoint there, so let's see how it can trigger that,
so I think I'm going to make it, if I reload, it doesn't work to trigger it,
so I'm going to do is the following, I'm going to make our default screen be home
so that we can press the button to go to the message and trigger the user fact call,
that way, because just reloading just doesn't trigger the DevTools, so let's do that,
so we're going to go to app and change the default route name here to be home again,
save it, now let's see, reload the app
by shaking it, or I can use the terminal, I think press R in the terminal, let me try it, R in the
terminal, okay, now I'm going to press messages, I'm going to watch the DevTools to see if it's
triggering, okay, let's see again, messages, sometimes it doesn't trigger,
you don't understand why, so we got to try again, let me try opening the DevTools again by using
OpenDS Debugger, here it is again, sources,
not really triggering, this happened before and I don't know why it started working again,
let's see, image gallery,
let's put a breakpoint outside, now it's triggering it, if I put a breakpoint in the fetch,
now it's stop here, last play to keep going, so it's rendering,
okay, so something is making it always render, so maybe something,
okay, let's look at the code,
I'm going to remove user fact,
let me watch it again,
reload here, reload,
load, messages, now it's triggering, play,
okay, remove that,
put user fact back,
let me put this down here,
put the catch, by the way, press command slash or control slash or windows to
comment this or an uncomment, so let's see, put that in a new line,
let me verify,
okay,
let's see if the tunneling is working, we didn't change that, still tunneling,
if I go here and check this on the postman, the browser, let's see,
okay,
it's doing this thing where we got a, okay, so the local tunnel now requires you to do this,
that's probably why it's not working, so we got to go here,
if running local tunnel and local computer visit this, so we got to visit this thing,
and it's going to give you this, and you copy that and put it here and click submit,
and I think that should work now, it didn't used to be this way, it used to work right off the bat,
but that's just the way it is now, okay, anyway, now that should work, if you go back,
let's see the messages thing here,
I'm going to put it back,
save it, let's try it out,
it's going to return empty because I don't have any, so
let me create some, because I'm using mac right now, I had to recreate the database,
so let's go to pgadmin here, and I will create some posts,
full stack db3 schema, tables, messages, let's make a user here,
add a new one, call it Anna, mail.com, this is Anna, read it out now,
and for messages here, let's see,
I'm going to create a new one, hello world, user one, now, and now,
okay, I got a message there, so I should be able to see it,
messages, let's see, I think it's paused in the breakpoint for the dev tools,
now it's there, and if I press play, I should remove this by the way,
it's complaining, view doesn't exist because I didn't import,
so we got to fix that, so it's hitting this at least, so we'll fix that,
so
scroll up, add view here, save, try again,
I should go to dev tools, it's now stopped there, let me see what I can see from message list,
I can see there, there's a one object with the message, hello world as the body property,
so I think I'm satisfied with that, remove the breakpoints,
press play, and finally, we should be able to see it,
messages there, okay, so that's hello world,
now let me quickly show you how we can create a message,
basically it's the same code for the web client,
same except we don't use, we use view and text,
basically, and we're going to use a different input element because HTML input type text,
for example, or a text area, and here's another component, let's go here,
by the way, there was a problem with the mapping, I just add a key to the view here,
so you can add a key to the view, and you can use the message id,
now another thing, if you don't like the inline styles, people usually isolate them,
like a style sheet in CSS, so you can refactor, so let me show you different ways of doing the style,
so you can do inline like this, or you can take that out, and you can make a variable for that,
let's call it styles, and then you can make a property in that styles object, let's call it
a message container, how about that, and then here outside you can define styles as an object,
and you can pass message container property and pass that value as this object, so when you
say styles.messageContainer, it gives you back this object here, and that's a way of organizing it
better, and then if you had other stuff to give styling, for example this text message,
you can say styles.errorMessage, and it would go up there, add to the styles object, the error
message property, with the definition with this object, that way when you say styles.errorMessage,
you get this object with the color red, this is one way, another way is you can go even further
and isolate this to a separate file, so I could go here under mobile, create a new folder called
styles, and we can go here and create for example messages.js, and I could define this there by
cut and paste, and you can export default that, export default styles, and then from messages,
what I do is import styles from dot dot actually, because we got to go where here,
under screens, we got to go one level up in the directory tree, so dot dot means one level up,
so now we're at mobile, and then from mobile we go to slash styles, and then messages.js,
you don't have to say .js, so you can do that as well, and it will work the same way, so you're
kind of isolated in a separate file like a CSS file. Okay with that out of the way, let's do the
creation of a message, so for that I'm going to scroll down here, and to the top before the
messages, I'm going to add a text field so that you can type the new thing, so this component is
the text input one, like this, and you're going to give it a style so that it actually appears,
so we got to give it a height, let's do 120, and if you want to add a border color of gray,
border width if you want, and I'll make it width 100%, I think I can do that as well,
and let's isolate this style into the styles object, let's call it styles dot text input,
and I'll go to styles slash messages, I'll open here, let me see if I can put editor layout
split down so you can have it down here, so add text input and pass that object there,
and we got import text input here from react native, so included there,
and going back here, what else do we need, okay we need to make it multi-line property
to take more than one line, and you have to control this just like we control in the react web,
the input type text with a known change, and a value here, you got to control with value,
and on change text, that's the difference, zone change text versus zone change only,
so the value will come from the state variable, we can say let's call it new comment,
and on change text is from the function that we're going to call when do you change this,
so on comment change, I will call it one new comment change,
now let's define new comment and on comment change, go up here, let's add a new react use state,
for the comment initially empty string, let's call it new comment, and then set new comment,
now for the function, we can add here, before return, we add a function,
let's call it, what do you call it, on new comment change,
and the argument here is a text that was typed in, which is different from the
web for react, that takes an event, the target, the value, here is just text,
and then you can, when the user types something, it's going to call this function,
and the text will be what the user typed, so you can just say set new comment with the text,
and that should control the input,
let's see, I have that here, click there, I can type hello there,
nice, I can have multiple lines,
cool, now let's go back and implement the submission,
so I'm going to add here after the text input, a buzz in,
but style is comment, and when I on press, I will call a function that I'll define,
on comment press, that's the final outside function on comment press,
when you press the button to comment, we're going to make a request to back in batch,
back tick, API URL, slash messages, now we've got to make a post request,
therefore the second argument to fetch will be an object with method,
property, and this object will be imposed, some headers, so we are sending JSON, so content type,
under quotes, application slash JSON, and then we're going to pass the body of the request,
with the JSON string applied, what the user type for the comment, which can be
gotten for a new comment variable, but this has to be under an object,
because I think the back end expects it to be body if I'm not mistaken, we can verify,
let's verify, server slash index, we go to the definition for the endpoint,
app post slash messages, I will verify what properties,
it is expecting its body, so we're safe, so it can go back its body, property for the object,
all right, and I think that's it for options to the fetch, and this returns a promise that we
can do a dot then, and pass a function that has the response, and then can do the error handling,
if response not okay, assume happy path for now, I do response JSON, and that will extract from
the body, the response, if there's one, I think usually it returns back the object itself,
including an ID from the database, so I can do that then function with the created message,
and we can do whatever that typically we include in set the new messages, I can add to the top of
the list, so I can set messages as an array, copy from the existing messages, so you can say dot,
dot, dot to copy the elements from the array messages, and then before that, that the first
element which will appear at the top is the created message object, and here outside you can
add a dot catch if you want to catch any errors that might record in the promise chain, so you
can put a function there, and handle error in promise chain, and I need this, and after we
do the set message, you might want to clear the input, so you can say set new comment to be empty
again, it's complaining about button not being defined, so at the top, add button here to the
list of imports for react native, and let's test it out to see if it's working,
I'll pass messages, I'm going to say hey there, and press comment,
is it working? It didn't seem to work, right?
So what's going on?
Oh that was working, I think it's something to do with my pressing or the keyboard appearing,
I got to press twice or something, test, I press one, I think, I don't know if you can see on the
recording, there's a keyboard, so I press once, the keyboard goes away, I press again,
it might be
loading or something, we don't have a loading state, right? The press here, comment,
hey, comment, now it's working, test to return comment,
I don't know, how's everybody doing? Is it working for you okay? I don't know if it's my
touchscreen, that's, I have to press twice or three times, but that shouldn't be that way,
we can add a loading state if you want,
let me add a loading state over here,
oops that's a dev tools,
if you want to add a loading state while you press comment, we can go here, add a new variable,
react, use state, the loading state will initially be false, and then it can set
submitting, let's call it submitting, set submitting, so as long as submitting is true,
that means I press the button and it's still waiting for the response,
and when we get it back, we set it back to false, so when you make a request here,
when you press, comment press, we're going to set the submitting to true,
and then when you get back a response, you're going to set submitting to false,
and also set false when you do the catch of the error, okay, otherwise we'll be showing the
loading state, even though we got an error or something, and then here in the, so there are
different ways you could approach that, maybe you can make the text input disabled, or disable the
button as well, so people like to show a spinner to indicate, you need some sort of indicator so
the user knows, oh I'm waiting, I'm loading, okay, if you, since we don't, we don't have a spinner
right now, I think you could use that activity indicator or something, let me see, activity
indicator, let's try this one, and I'm going to include that only when submitting is true,
so I'm going to start circuit, so when this variable is true, it's going to show that,
when it's false, it doesn't show anything, and this one comes from React Native as well,
so let's try that, see what happens,
okay, gear, hey,
I see that, momentarily appear, it's hard for you to see, so if you want to simulate like a
slow connection, you can either add a timeout on the front end or the back end, or you can simulate
that slow connection using the dev tools like we did for the web, let me show you here a cheap way
through the front end, you can just go here, wherever you do the, you receive the message here,
you're about to set submitting back to false, and do the setting of the message here, you can
simulate a very long delay by set timeout, you can call set timeout here with a function,
like that's an arrow function, it doesn't matter if it's arrow function, and the second argument is
how long you want to wait before you actually do the instructions for the function, like 30,000
is three seconds, because you got a milliseconds, you got to divide by 1000, so I moved everything
inside there to simulate a delay of three seconds, that way we can see the spinner,
let's try again,
I'm going to see,
hello, and see the spinner there, spinner, spinner, spinner, and hello,
and that's a loading state, once the, we get everything set submitting back to false, the
spinner is gone, so the user knows, okay, it's, the operation is complete,
that's just for debugging testing, so you want to remove that, so once you're done,
I'm going to remove the timeout, we don't want to have that in production, so I remove it.
No comments yet (loading...)
No comments yet (loading...)
Did you like the lesson? 😆👍
Consider a donation to support our work: