We'll dive into the process of creating a custom useForm hook in React. We'll add a generic API and make a validation mechanism to make every form management easy.
Forms management can be tricky. During the development of a simple login form, of course, there is no option to have problems. Anyway, problems occur when there is a requirement for multi-step forms, dynamic fields, async validation or customization.
Your first choice will be a library. It's not bad, generally, that's a good idea. However, if you need more advanced features or to fix bugs - there is a headache.
In addition, there is a risk connected with library usage. They often lose support over time, then you need to migrate to other technologies. As a result, you might end up using other libs with code that is usually useless for you.
I experienced this many, many times... Projects start, formik or other is installed, there is a feature which you need and right now it starts... The big pain of creating workarounds and adding additional dependencies, maintaining versions or even worse - rewriting your codebase because the lib which you used creates an impact on architecture - redux-form.
So in this article, I'll try to show you, that there is nothing bad with creating something that already exists, because sometimes, under good conditions, it can be worthwhile - "Software is a composition of iterations, hard work and knowledge (someone from the project, after not delivered sprint)".
Let's create useForm hook and check how it will work with forms.
Remember all custom solutions require additional maintenance. Use it wisely.
1. What are we building?
It will be the multi-step form for user account creation. You can check how it works on Jupi.io. This app uses a hook which we implement for every form.
I'm fancy multi-step form
2. Let's design our basic API
This is a really important step. We should cover all features and design dev friendly API.
3. Creating test cases
Tests during development guarantee that you don't break anything after providing code changes.
Please check the tests implementation in test file if you're curious. This is skipped to save your time.
4. Adding type definitions
Before implementing real code, firstly you need to create the type definitions. It will be much easier to write code to fit them instead of adding it later. With unit tests and types, you can take it easy 👽. Green means it works.
5. Implementing values change API
It's time to write real code. Here you have basic logic which allows to update values via set and change functions. Second function contains additional logic which validates event object and informs you in runtime.
Yes, you used useRef hook for state management instead of useState. It's because useRef changes are immediete not async like via useState setter. It gives you opportunity to read always up to date data inside components or other custom hooks.
This interesting usage has been described perfectly in React useRef hook article.
6. You need validation!
You need mechanism which will run functions passed via validation object to useForm hook and here it is.
You used for loops because:
They are little bit faster than forEach() | reduce() | map() or others
We have an option to stop execution at any time
It can look a little bit old but the performance is much better. I'm 100% sure that C++ devs enjoy that ⌨️.
7. Connect validation
Right now you just need to connect your validate function with useForm hook.
8. Attach metadata
Metadata is important. You definetelly need that to show different components on UI or highlight interactions.
9. Implement confirmation
Confirmation is equal to running validation for the whole form. It's important because sometimes you run validation always and sometimes only after the first submission. Depends on UX which you want to achieve.
10. Be able to reset
Simple function which resets state to initial.
11. Push subscribe button
Right now you can subscribe for single field changes and perform side effects. Imagine a situation when a user types something in input and you need to perform the request. Here is the perfect place and also you can add rxjs operators.
Right now you can use useForm for all cases.
Right now you have a base API. You can use Context API if you don't like prop drilling or create higher order component with additional logic.
Use these tools wisely. You need to understand the problems and benefits of technology and the techniques that you are using. Make sure that your project fits into solutions like those before you use them.
Feel free to contact me if you have any questions/proposals. Have a nice day and good health!