- There are many ways to handle forms in React. Most common way is to use a third party library like
react-hook-form
orFormik
. These libraries provide a lot of functionality out of the box and are easy to use. However, it is good to know how to handle forms without these libraries as well. We will start withuseState
hook with our own custom hook, and later we will look atreact-hook-form
.
Study useState with forms
-
Continue last exercise. Create a new branch 'forms' with git.
-
Create files:
Login.jsx
andLogout.jsx
toviews
formHooks.js
tohooks
LoginForm.jsx
andRegisterForm.jsx
tocomponents
-
Login.jsx will hold LoginForm and RegisterForm components
- Add the usual imports, component function and export to Login.jsx, LoginForm.jsx and RegisterForm.jsx
- Login.jsx:
// imports const Login = () => { return ( <> <LoginForm/> <RegisterForm/> </> ); }; export default Login;
-
Add
login
to routing in App.jsx- Add
Login
to imports - Add
<Route path="/login" element={<Login/>}/>
toRoutes
- Add
<Link to="/login">Login</Link>
toNav
inLayout.jsx
- Add
-
Do the same for
Logout.jsx
andlogout
route -
Add
<form>
to LoginForm.jsx with username and password fields and submit button:// LoginForm.jsx const LoginForm = () => { return ( <> <h1>Login</h1> <form onSubmit={ () => {} }> <div> <label htmlFor="loginuser">Username</label> <input name="username" type="text" id="loginuser" onChange={ () => {} } autoComplete="username" /> </div> <div> <label htmlFor="loginpassword">Password</label> <input name="password" type="password" id="loginpassword" onChange={ () => {} } autoComplete="current-password" /> </div> <button type="submit">Login</button> </form> </> ); };
-
In
formHooks.js
create a new hookuseForm
:import { useState } from 'react'; const useForm = (callback, initState) => { const [inputs, setInputs] = useState(initState); const handleSubmit = (event) => { if (event) { event.preventDefault(); } callback(); }; const handleInputChange = (event) => { event.persist(); console.log(event.target.name, event.target.value); setInputs((inputs) => ({ ...inputs, [event.target.name]: event.target.value, })); }; return { handleSubmit, handleInputChange, inputs, }; }; export default useForm;
- What is happening here:
useForm
takes two parameters: a callback function and an initial state object- The callback function is called when the form is submitted. That function is made in E.g. LoginForm to
send the form data to the API. See
handleSubmit
below.
- The callback function is called when the form is submitted. That function is made in E.g. LoginForm to
send the form data to the API. See
handleSubmit
is a function that prevents the default form submission and then calls the callback functionhandleInputChange
is a function that takes an event as a parameter and updates the state- Note that the argument for
setInputs
is a function. This is because we need to add to the existing state, not replace it.
- Note that the argument for
- What is happening here:
-
Then in LoginForm add these to the component function:
const initValues = { username: '', password: '', }; const doLogin = () => { console.log(inputs); // TODO: add login functionalities here }; const {inputs, handleInputChange, handleSubmit} = useForm(doLogin, initValues); console.log(inputs);
-
Add
handleInputChange
andhandleSubmit
to the<form>
and<input>
components. Which one goes where? -
Test the form. Check the console. What is happening?
-
In APiHooks.js create a new hook
useAuthentication
. CreatepostLogin
function touseAuthentication
:const postLogin = async (inputs) => { const fetchOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(inputs), }; const loginResult = await fetchData(import.meta.env.VITE_AUTH_API + '/auth/login', fetchOptions); return loginResult; };
- Make
doLogin
function callpostLogin
and pass the form data as a parameter. ThenpostLogin
should log the result to the console.- Register new user using Postman. Endpoint:
http://10.120.32.94/auth-api/api/v1/users
. - Documentation.
- Register new user using Postman. Endpoint:
- remember to handle errors from promises with try/catch
- Make
-
When logging in, save token to localStorage. Also redirect to 'Home'
-
display user's info (username, email etc.) in Profile.js. For this functionality you need to add a new hook
useUser
toapiHooks
. Create a new functiongetUserByToken
touseUser
hook.getUserByToken
should get the user data from the Auth API from this endpoint: /users/token. Use the token from localStorage as a parameter for thefetchData
function. Then usegetUserByToken
in Profile.js to get the user data and display it. -
Make
RegisterForm
component have similar functionality asLoginForm
, but it should create a new user, so it also features anemail
field. Use the sameuseForm
hook to get the values from input fields.- Instead of
doLogin
usedoRegister
as the name for the function that is called when the form is submitted. - Create
postUser
function touseUser
hook.postUser
should post the form data to the Auth API to this endpoint: /users. - Then
doRegister
should log the result to the console.
- Instead of
-
Use conditional rendering to show either
LoginForm
orRegisterForm
inLogin.jsx
. Add a button to switch between the two forms.
- Run
npm build
ornpm run build
- Move build folder to your public_html
- Test your app:
http://users.metropolia.fi/~username/forms
- Modify README.md. Change the link in
Open [X](X) to view it in the browser.
to point to the above link. - git add, commit & push to remote repository
- Submit the link to correct branch of your repository to Oma