How to Build a Multi-Page Form with React Hooks | Multi-Step Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
forms we use in react applications often need to be completed in several steps essentially multi-step or multi-page forms let's learn how to create a multiple page form in react [Music] hello and welcome I'm Dave today we will create a multi-step form in react I'll provide links to example source code and all resources in the description below I'm starting today's tutorial with the code from my react form change Handler tutorial and if you've completed that then you've already got this billing form and it was just the one page form but today we're going to make this a multi-page form as you can see goes on to a shipping info form where we can say it is the same as the billing address or not and then it goes on to an opt-in page as well before a submit button the submit button is just going to log to the console as I did with the change Handler tutorial of course you would submit that to a rest API or wherever you wanted to send your data but this is really about creating the form and I've provided some CSS in this index CSS that you'll also be able to get from the code repository that's linked to in the description I've added a few other components that you see over here highlighted in green I've got a shipping component and the opt-in component that are the other form screens that we share here and then I've also got a container component that is called form inputs we'll be creating all of that but what we want to do first is just look at what we already had I'll hide the file tree so we can look at all of these I've got an app.js and I'm just returning the form you could have a larger application in the form would just be one of the components of that application so I've got this as the parent from there I've got the form component and this is what we had in the change Handler tutorial where it was just the billing information so we're going to expand on this and we'll see what we can abstract from this component because we want to use some Global State we'll be using the use context hook for that as well so we'll get some of this information some of the things we're doing inside of this form component will be abstracted out into a global State and then we've got the the billing component that we had created before so we're going to modify those and add to it so let's start today by showing the file tree and then inside the file tree I'm just going to highlight the app.js so I'm in the parent here and not inside the components directory and I want to create a new directory and I'm going to call this directory context and you can have more than one context in an app we're going to make a form context and it will provide the context the global state for this form so you could just separate that out from the rest of the application as you'll see what I do with that here let's create now our form context inside this context directory so I'll call it form context.js and I'll hide the file tree so we have some more room and we can still see the form over here and I'm going to import several things I'll have create context I also want use State and use effect and I'm going to press alt Z so anytime a line gets longer it's just going to wrap down to the next line after those Imports we'll start out by saying const form context we'll set this equal to create context parentheses and then we'll have an empty object inside after that we can say export const and now we'll have our form provider and then we'll set this equal to once again parentheses and an object and we'll destructure the children the children will be all of the nested components inside of the form provider what we have wrapped the form provider around and you'll see how I do that to the form and now let's go ahead and have our Arrow function here and inside this function we can Define all the things that we want to pass on with the form provider and to do that we'll have a return then I'll have parentheses once again and we will have our form context dot provider and then we will have values that we pass on so I will set that up in just a little bit but right now I'll just say value set that equal to we've got our curly braces and then it will be an object that we destructure there inside so another curly brace after that we can close the form provider so we get the closing form context provider as well and here is where we represent the children again these are the components that we end up wrapping our form provider around so our form is going to be here and that would be represented by the children which you'll see when we apply this if you haven't used the use context hook before or created a context maybe it will make more sense when you see that right now I just want to put export default form context here at the bottom so this is the basic outline for creating a context we use the create context to create the form context then we also Define our form provider that we're going to use we return essentially the provider here and I'm going to pass values in that will be available to the children components or the child components so we need to Define some things in here that we're going to abstract out of that billing component I'll pull up the form here I guess out of the form component I should say not the billing component so one of those things would be the data so let's go ahead and grab the data that we had inside of the form I'm just going to control X to cut that out go into the form context here and I'm going to paste it right in and that's our data and set data now of course we're going to have more State than just the billing information now so I'm grabbing the rest of that state and we're going to just paste it right in here so you can see everything now we'll have all the billing information then we have a field that says same as billing which is a Boolean it's either true or false and then we have the ship information and then we have opt-in news and that's another Boolean true or false so a lot here in our state object that we're still using the U State hook with and data and set data data of course represents the state and set data will set the state after that there's a couple of things I want to put above this we're going to need to have a lookup object and I'll just call it title and inside of this object will have a 0 which would represent our first page and that is going to be the billing info and notice our title here on this page it says billing info that's what we're going to create with this and we'll also use this for something else as well and then we'll have shipping info if I can spell info and then finally we'll have opt-in and those are our three page titles that we will use after that there's another important piece of State we need to create so I'll say const and this is going to be page and set page we'll set this equal to use State and we'll just start with zero and this will represent the page number that we're on we'll need to keep track of that we'll also be able to use this title as I said for more than one thing to determine how many pages there are now everything we have created here the title page set page data and set data are things we want to make available through our form context so these are values that we will pass along here so we had title page set page also data and set data and we'll be able to use these where we need them by pulling in our context now let's see what else we have in our form component that we might want to go ahead and pull into our context anything that's not related just directly to the form that we might need in each page of the form we would want to pull out and possibly put inside of that context the handle submit that can stay with the form that's dedicated directly to the form the handle change we could actually create another custom hook for because we might use that elsewhere in our application it is not specific to this form really although it does have set data here that we would have to create a different type of parameter to pass in as set state so this does really tie it to our form context and maybe we would just leave it in the form context for this tutorial but know if you wanted to create a handle change that could be used throughout an application you you would just need to pass in the different type of set State function that you would be using as well instead of a dedicated set data like we're referencing here after that we can see where we were destructuring to define a can save I'm going to press alt Z so this wraps as well and we were using can save to find if we could actually submit the form or not and then we had content so there are a few extra things we can pull out here let's go ahead and grab our handle change and then the destructuring and the can save variable and we will control X to cut all of those out of our form JS and we can put them inside of the context and now our handle change function will stay the way it is it references set data that we have up here inside of the same context so that is fine the destructuring now we have more properties in our state object than just the billing address 2 that is not required so we also have a ship address too that is not required and we also have a check box for same as billing address and that's not required and we have an opt-in check for our newsletter and that's not required so we need to adjust how we destructure this so I'm going to scroll up for a little bit of room and let's go ahead and break these out on separate lines so I'll have the billing address too after that I'm going to have on a separate line again same as billing comma and then I want the ship address to and then one more it will be the opt-in news and then we'll have our other props equal to data now I really want to change this other props isn't too descriptive and that's not what I want either I want to name these as required inputs because that's what's left we want to find out what inputs are required that should have something entered into them so I'm just renaming that here likewise with can save now I'm just going to change that to can submit so just getting a little more descriptive for what we're doing and now let's think about this can submit because we may need to adjust that as well I'm going to drag this over to full screen just so we can see it a little bit better we're not changing that form in the browser right now so you can see we have the can submit equals and we spread in the object values for the required inputs and we make sure each one evaluates to true so at least it has something entered it's not an empty string but now we're also going to need to take the page numbers into account and to do that I'm going to add on to the end of this and I'll paste this in and then we can review I've got the double Ampersand so it says not only do all of these values need to be true also the page needs to be equal to the last page and we calculate that last page by grabbing that title object and using object.keys passing the title object in that we defined above so we can see that there are three pages here but then what we're doing is saying dot length minus one so that takes the title object and the keys of the title object and makes it an array and then we check the length and then of course we need to subtract one and only then if we're on that second page as we've currently defined our title object will the can submit be true and with that said let's go ahead and add can submit to what we are providing here with our form provider with these changes now in place let's save our form context and I like to create a custom Hook when I'm using a context so it's not as cumbersome for every component that we add the context to so I'll go back to the file tree and now I'm going to highlight the app.js once again and create another new directory and I'll call this one hooks inside of the hooks directory I'll create another new file and I will call this use form context.js and this is a very simple hook I'm just going to import use context and there it is in our list comes from react after that I am going to import the form context that we created and after that import I could say rafce using es7 react Snippets it is an extension if you don't have that and then inside of this use form context very simple here we just say return use context and pass in the form context and this is essentially so we don't have to import these every time and then we have a couple separate lines as well and we just have to do this with the hook so we can always just use form context instead of the extra few steps and now let's go back to our form component and we'll start to use that context notice we're not using State anymore so we can remove this import at the top and we will say import use form context and immediately comes from our hooks directory and now that we have that we can use that at the top so I'm going to say const and we'll de-structure everything we need I'm going to break this onto separate lines because there's quite a bit we'll have page and then we'll have set page and then we'll need our data we also need that title object and we need can submit for now and then I'll set all of this equal to use form context okay you can see we were previously importing in the billing component because that's the only page our form previously had and then we were using billing down here inside of the form that's going to change now so you can see we've got a form and then form inputs over here and we're going to Nest all of those other components inside of form inputs so I'm going to import form inputs from dot slash form inputs there it is and after we've done that we can change this out in the form as well so we'll no longer have billing here we'll instead have a form inputs component and I can just close that out because we're not going to be passing props down we're going to get what we need from the context in each component that we need it I'm also going to wrap our H2 heading in a header element and so press enter and just take this H2 cut it and paste it right inside there save to get the formatting but now we can create this dynamically it doesn't need to just say billing info so inside of the H2 here we can reference the title object that we had and then we can reference the page value that we have in state and this will generate the title for us so if the page is zero then we would have the title of billing info which related to that 0 in that title lookup object likewise if the pages 1 it should say shipping info and if the page is 2 it will say opt-in and now I'm going to move this button and the other buttons that we're going to need from the bottom up to the top so they're going to be part of the header so inside of the header I'm going to create a div and it's going to have a class name of button Dash container and then inside of the div we can put all of the buttons so I'm just going to grab the button that we we already have control X to cut that out and paste it in here notice we're still using can save and this now needs to be can submit that we created as we renamed that and after I save that we get the proper formatting there after that we want a couple of other buttons though and we need to be concerned about the types now because we're going to have more than one button in our form if you only have one button it defaults to being the submit type but if you have more than one button then we need to Clearly say what the types are so this type is going to be submit but these other buttons will not so I'll start out now with another button say button and let's give this a class name of Button as well so it has the class name button but then we need to also say the type and the type is going to be button and let's put the word preve here for previous and then I'm just going to copy this down so we also have another button and this button is going to say next now our submit button does not have a on click Handler and that's because by default when you click the submit button that submits the form so that would go directly then to our handle submit these other buttons will need on click handlers and we'll need to create those handlers that will be called in the on click now before we create the handlers just to verify we are bringing in set page and that's what we need in the handlers so now let's put them before the handle submit and we'll start with handle previous so I'll say handle and then pre-v for previous set this equal to an anonymous function and inside this function all we need to do is say set page use the previous state and then we'll say previous minus one and that is to set the page count back one as we go use the previous button so I'll just use shift alt in the down arrow to copy this down and now this would be handle next so I'll just say handle next here set page would still be previous but now it will be previous plus one in this function now let me go ahead and create some space between those but those are our handlers for the previous and next buttons so now let's scroll back down and put those in the on click for each of these buttons so we can say on click equals have our curly braces and here I'll say handle previous and then we can do the same thing here for next we'll just be on click equals curly braces and handle next and with that now we should take a look at the form inputs that we have after the header because that's essentially all our form has so let's look at this form input component and inside the form inputs you can see we're importing billing we also have shipping and opt-in and then we also have the context and all we need here in form inputs is the page value from our form context and now we have a display object lookup so we're showing either the billing shipping or opt-in component so much like we generated the title we're generating which component is displayed inside of our form inputs div here that is our container and then we just return that content so now let's take a quick look at our new components shipping and opt-in so if we look at shipping you can see we're bringing in the form context and we're destructuring the data and the handle change function that we need as each different controlled input changes and then you can see we also have checked and we have data.same as billing there's something interesting about this because as we apply the data.same as billing which is saying our shipping address is the same as the billing address if you look at the rest of the inputs here in the shipping component we're setting disabled equals to that value so we're disabling the different inputs if we check same as billing but it gets that setting so I'll drag this over and we can see as I go to the next page and this is shipping these inputs are currently disabled because we check that but then if we uncheck this it is no longer disabled and I can type into any one of these we just see the placeholder values here so that is how that value works and it also impacts all of the other inputs on this particular page and then if of course this information is filled in currently the next button is not enabled either so if we check it then once we have the information we need only then is the next button working and when we go back to the first screen we don't see the previous Button as well so we're going to need to put in some checks for that likewise if we don't have the information that we need on the first page or at least any information we might still highlight that we're not meeting the validation and the next button works but if we remove that then the next button is disabled as well and I can go deeper into validation in another tutorial however this one at least makes sure that we have information in each required field before the next button can be clicked I'll go ahead and finish filling that out and now let's go back to our code that we have here in Visual Studio code and we can put in those extra checks before we add the extra checks actually one other thing that I thought of is we haven't changed our billing form yet to use our form context so I'm just going to copy this import for the form context and then it will also need data and handle change as we use that so here in Billing you can see we were previously passing these down when we had a one-page form we just use those as props but now we have used a context and created that Global state so I can cut this directly out of there and instead I can say const those and then say equal to use form context and really that's a very clear illustration of how a context replaces passing down props now let's go back to the form context where we can begin adding some of these other checks the first one we want to concern ourselves with is the same as billing so when we check the box we fill in all of the shipping State and we can do that with the use effect that we imported here at the top so underneath our use statehood use we'll just put this right underneath the state and I'm going to paste this in it's a little long so I will scroll through you can see it's a use effect and we're looking at the same as billing State here the data dot same as billing in the dependency array so if this one value changes then we use an if statement and if it is true then we set all of the data of course the billing data here fills in the shipping data and we spread in that previous data but if it is false then we set it all back to empty strings so that way when we uncheck that box it empties out and I'll go ahead and save this and I'll drag this over just one more time so we get a demonstration on this second page currently it's checked so it filled in all of that information if we uncheck then once again all of that information is gone and we can type into each input checked they're disabled and it fills in the information and fills in that state so now that we've accomplished that with use effect we need to look at how we can handle the different buttons and when they're available and when they're not available on each page of the form let's scroll down and let's first determine if we can use the buttons or not now we're not passing along that handle change yet it doesn't look like let's make sure we set that on its way here and our provider also so I'll type handle change right here so it is available to those other components now what we're talking about is can we use the buttons and what we want to do just like we destructured here and determined what the required inputs were for the entire form all the pages together now we want to look at each page and say can we use that next button is everything complete on the first page before we can move to the second and we can do that much like we did this here it just looks a little differently so I'll paste this in and we'll go over it so can we move on from the first page and I just said Can next page one so I'm taking the state data once again and I'm using object.keys instead of object.values but it does create this array and then I filter the array and we're looking to see if the key starts with billing because that first page is all about the billing info and the required part that is not required or I should say the part that is not required is the bill address 2 that starts with Bill so that's the only one we want to say not equal to after that I need to map over that data because this array that's created by filter just has the keys and so now we map over and say data and we use brackets around the key and now we get the value so then I should have an array with the values and we make sure every one of those is true in other words not empty now I do the same thing for the second page but I make sure that the keys start with ship and that is how we put our state together so we had ship here or we see that here in this use effect but here's our state actually so we had Bill starts all of these with the word bill and we start all of these with the word ship and so that's how I'm using that and I'm chaining these array methods together to determine that so now I'll scroll down for some more room and we're going to use these two values we just created for each page as we determine to disable the buttons or not so as I paste this in I'll save for the formatting the disable previous button is easy it's just if the page is equal to zero the first page then we want disable previous to be true disable next is definitely different because it's available on several pages and the qualifications could be different on each page so the first one we determine is if we're on the last page we already knew that from our can submit as well as we determined here if we were on the last page so we use that same determination but then we put these in parentheses because we're using or in between so the next possibility is that we're on the first page but then can next page one that we defined here is false the second is much the same it's just if we're on the second page which is page one then can next page two is false so any one of these three conditions will disable the next page H but we're still not quite finished we have a few CSS classes to create and I'll paste those in and we can look at them I'll save for the formatting so they're back to the left we want to hide the previous button so I have a previous hide class and it is equal to remove button which is a class in my CSS if the page is equal to zero if we're on the first page we don't want to see the previous button I have a next hide class and there if the page is equal to the last page then that is equal to that class remove button so we don't want to see the next button on the last page and then I have a submit hide and this class is equal to remove button if we're anywhere except the last page because that's the only place that we want to see the submit button so with all three of those we've already saved we need to pass these values along now we're using the can next page value that we created and the can next page 2 to help deter determine the value of disabled next so we don't really need to pass those along what we do need to pass along in the context is the disable previous disable next and then the three classes so let's go ahead and add all of that here we'll say disable previous disable next and then we'll have previous hide next hide and submit high now that we've added all of those we can save and go back to our form and apply them the first thing we need to do of course is bring them here inside of the context so we'll have disable previous then we had disable next and we had previous hide next hide and submit hide I'll go ahead and save those changes and then let's apply these to the buttons below so as we scroll down now find the buttons here and we've got our handle previous button and we need to go ahead and apply disabled so we'll say disabled and that's going to be equal to and set the curly braces and we'll have disable previous now we can do the same I'm just going to copy here and paste into the next and this would be disable next and finally we've already got our disabled here for submit which is the opposite of the value of can submit now when we apply these classes we need to go ahead and use curly braces here so we'll start with the curly brace and then we want to have back ticks instead of the double quotes that we were using so I'll go ahead and get rid of those double quotes we'll use the button class and now this is a template literal and so we can go ahead and insert our previous hide class as well and now I'm going to copy this as well because the other buttons also have the button class I'll put this over the button class here we'll have button instead of previous hide this would be next hide and then finally we'll put it over the one on the submit button and this will be submit hide we've essentially made all of our changes now but there's one important thing we need to do with our context first and that is provided to the form so in the app.js besides importing the form itself let's go ahead and import our form provider so this would be form provider and then it is going to come from our context so dot slash context and then slash form context once we have that form provider let's go ahead and wrap the form in it now as I mentioned before you could have an app that has many more components or many different parts that are working and all we need to do is provide this form provider to the form so this doesn't mean it needs to be provided to the complete app if you had other components that do not need this information there's no reason to provide it there and an app can have far more than just one context as well which means there could be other providers that are providing a different Global state to a different part of the app but here we're providing that context that we created and everything that it offers to our form okay with those changes in place I'm going to drag vs code to the left here is our example app that's running in another instance of vs code I'll make sure to close out of that go ahead and close the example now I'll go ahead and hide the file tree and open up a terminal window I'm going to type npm start and we'll see if we get the same result now in the browser tab and here's our form it looks like the next button isn't over here to the right like I expected so there may be a change there let me look at the file tree quickly I believe in the form.js I'll hide that file tree again close the terminal just so I can see a little bit more and yes I did not apply a class to the header that I should have so I'll just put a class name here and set this equal to form Dash header this just relates back to my CSS and that should make a difference and yes now the buttons over here to the top right so we have our first page of the form we can't use the next button yet so it is disabled so that's working as it should let me go ahead and enter in some information here Dave gray one two three and whatever we want to put there I'll put la for the City California one two three four five and our next button is working okay we're on the next page the previous buttons working but the next button is disabled on page two even though it works on page one that's great let me go ahead and just click same as billing so it fills in all of that information disables those inputs and now the next button is ready to go when we use it we get to the last page and here is our opt-in page and we could check that we want to receive the newsletter previous button works next button works and now we have a submit button let me go ahead and pull this over as far as the submit goes I'll open up Dev tools and we'll see a console window here clear that out and I'll hit submit and we get all of our state currently logged into the devtools console window so that's what is expected and that is how you create a multi-step multi-page form in react or at least one way to do it now in the future we could add a progress bar to this to show the different steps being completed we might also add some additional validation as I pointed out before we're currently checking to make sure we have values in each of the inputs but not necessarily that the patterns must match before next works or anything like that so we could add a little bit more validation and those would be good future tutorials remember to keep striving for Progress over Perfection and a little progress every day will go a very long way please give this video a like if it's helped you and thank you for watch watching and subscribing you're helping my channel grow have a great day and let's write more code together very soon
Info
Channel: Dave Gray
Views: 26,960
Rating: undefined out of 5
Keywords: how to build a multi-page form with react hooks, multi-page form, multi-step form, multiple page form, multiple step form, react form, react forms, form, forms, react.js form, reactjs form, react.js forms, reactjs forms, multi step form, multi page form, react hooks, tutorial, react tutorial, react.js tutorial, reactjs tutorial, react form tutorial, react forms tutorial, react hooks tutorial, react how to tutorial, react how to, how to, multiple forms, how to build a form
Id: QSBc8bABwE0
Channel Id: undefined
Length: 34min 40sec (2080 seconds)
Published: Tue Sep 20 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.