0% found this document useful (0 votes)
21 views11 pages

T5 - State Hook and Localstorage

Uploaded by

noroyip965
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views11 pages

T5 - State Hook and Localstorage

Uploaded by

noroyip965
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

IT524048Q Full Stack Development

Worksheet 5

Recap creating a new React Project


You can launch a react project under your development folder (you can declare where the folder
is). Then you can execute the command as below:

npm init vite@latest [project name]

Answer the question as below:

Using Visual Studio Code


Open the folder in Visual Studio Code by File > Open Folder

Once you have opened the folder, you can execute the following command in the terminal (make
sure that you are executing the terminal by using PowerShell.

npm run dev

And clicking on the local link (Ctrl-Click) to launch the page.

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

Applying with Bootstrap


In this page we will begin creating a front page for a Car Rental Company using React and a CSS
component library with bootstrap. (https://getbootstrap.com/)

We use Bootstrap simply to make the components look nice and avoid having to re-code
common components by hand, such as form elements, buttons, modals, and so on.

Apply Bootstrap to the project


Enter the following command in the terminal:

npm i bootstrap
Open index.html and update the script to adopt Bootstrap to the application as below

<!-- other scripts here -->


<head>
<!-- other scripts here -->
<title>Vite + React + TS</title>
<link
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
rel="stylesheet" crossorigin="anonymous">
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

React Form
In previous worksheet, you should already familiarizing the conditional rendering. Now, let’s
have some modification to work with the login.

Create Login components.


In the components folder, create a new tsx file named Login.tsx with follows:

import React, { useState } from 'react';


import { Modal, Button, Form } from 'react-bootstrap';

interface LoginForm {
username: string;
password: string;
}

const Login = () => {


const [isLoggedIn, setIsLoggedIn] = useState(false);
const [formData, setFormData] = useState<LoginForm>({ username: '',
password: '' });
const [showModal, setShowModal] = useState(false);

const handleShow = () => {


setShowModal(true);
setFormData({ username: '', password: '' });
}
const handleClose = () => setShowModal(false);

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {


setFormData({
...formData,
[e.target.name]: e.target.value,
});
};

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {


e.preventDefault();
console.log(formData);
setIsLoggedIn(true);
handleClose();
};

const handleLogout = () => {


setIsLoggedIn(false);
}

if(isLoggedIn) {
return(
<>

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

<Button onClick={handleLogout} variant="info">Logout</Button>


</>
)
} else {
return (
<>
<Button onClick={handleShow} variant="info">Login</Button>
<Modal show={showModal} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Login</Modal.Title>
</Modal.Header>
<Form onSubmit={handleSubmit}>
<Modal.Body>
<Form.Label>Username:</Form.Label>
<Form.Control type="text" placeholder="Username"
name="username" value={formData.username}
onChange={handleInputChange} />
<Form.Label>Password:</Form.Label>
<Form.Control type="password" placeholder="Password"
name='password' value={formData.password}
onChange={handleInputChange} />
</Modal.Body>
<Modal.Footer>
<Button variant="primary" type="submit" >Login</Button>
<Button variant="secondary" type="reset"
onClick={handleClose}>Close</Button>
</Modal.Footer>
</Form>
</Modal>
</>
);
}
};

export default Login;

Remember to update App.tsx so you can make use with the new Login component.

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

Form validation
To add validation to the login form within the react-bootstrap modal, you can utilize the yup
library for schema validation along with form validation properties provided by react-bootstrap.

npm install yup


and add the validation script into the Login component.

import React, { useState } from 'react';


import { Modal, Button, Form } from 'react-bootstrap';
import * as yup from 'yup';

interface LoginForm {
username: string;
password: string;
}

const schema = yup.object().shape({


username: yup.string().required('Username is required'),
password: yup.string().required('Password is required'),
});

const Login = () => {


const [isLoggedIn, setIsLoggedIn] = useState(false);
const [formData, setFormData] = useState<LoginForm>({ username: '',
password: '' });
const [errors, setErrors] = useState<{ [key: string]: string }>({});
const [showModal, setShowModal] = useState(false);

const handleShow = () => {


setShowModal(true);
setFormData({ username: '', password: '' });
}
const handleClose = () => setShowModal(false);

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {


setFormData({
...formData,
[e.target.name]: e.target.value,
setErrors({});
});
};

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {


e.preventDefault();
schema
.validate(formData, { abortEarly: false })
.then(() => {
console.log(formData);
setIsLoggedIn(true);

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

handleClose();
setErrors({});
})
.catch((err) => {
const validationErrors: { [key: string]: string } = {};
err.inner.forEach((error) => {
validationErrors[error.path] = error.message;
});
setErrors(validationErrors);
});
};

const handleLogout = () => {


setIsLoggedIn(false);
}

if(isLoggedIn) {
return(
<>
<Button onClick={handleLogout} variant="info">Logout</Button>
</>
)
} else {
return (
<>
<Button onClick={handleShow} variant="info">Login</Button>
<Modal show={showModal} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Login</Modal.Title>
</Modal.Header>
<Form onSubmit={handleSubmit}>
<Modal.Body>

<Form.Label>Username:</Form.Label>
<Form.Control type="text" placeholder="Username"
name="username" value={formData.username}
onChange={handleInputChange} isInvalid={!!errors.username} />
<Form.Control.Feedback
type="invalid">{errors.username}</Form.Control.Feedback>
<Form.Label>Password:</Form.Label>
<Form.Control type="password" placeholder="Password"
name='password' value={formData.password}
onChange={handleInputChange} isInvalid={!!errors.password} />
<Form.Control.Feedback
type="invalid">{errors.password}</Form.Control.Feedback>
</Modal.Body>
<Modal.Footer>
<Button variant="primary" type="submit" >Login</Button>
<Button variant="secondary" type="reset"
onClick={handleClose}>Close</Button>
</Modal.Footer>

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

</Form>
</Modal>
</>
);
}
};

export default Login;

You can now try to login. You can find that the username and password is now show up in the
browser console.

Handling Login incorrect


If the username or password is not correct, you need to let the user know the login is failed and
ask the user to try again. In this stage, we can modify the code as below:

...

const Login = () => {


const [isLoggedIn, setIsLoggedIn] = useState(false);
const [formData, setFormData] = useState<LoginForm>({ username: '',
password: '' });
const [errors, setErrors] = useState<{ [key: string]: string }>({});
const [showModal, setShowModal] = useState(false);
const [loginError, setLoginError] = useState<string>('');

...

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {


e.preventDefault();
schema
.validate(formData, { abortEarly: false })
.then(() => {
if(formData.username === 'user' && formData.password ===
'abcd1234') {
console.log('Login successful');
setIsLoggedIn(true);
handleClose();
setErrors({});
} else {
setLoginError('Invalid username or password');
}
})
.catch((err) => {
const validationErrors: { [key: string]: string } = {};
err.inner.forEach((error) => {
validationErrors[error.path] = error.message;
});
setErrors(validationErrors);

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

});
};
...
<Form.Label>Username:</Form.Label>
<Form.Control type="text" placeholder="Enter your
username"
name="username" value={formData.username}
onChange={handleInputChange} isInvalid={!!errors.username} />
<Form.Control.Feedback
type="invalid">{errors.username}</Form.Control.Feedback>
<Form.Label>Password:</Form.Label>
<Form.Control type="password" placeholder="Password"
name='password' value={formData.password}
onChange={handleInputChange} isInvalid={!!errors.password} />
<Form.Control.Feedback
type="invalid">{errors.password}</Form.Control.Feedback>
{loginError && <Form.Label style={{color:
"red"}}>{loginError}</Form.Label>}
</Modal.Body>
<Modal.Footer>
<Button variant="primary" type="submit" >Login</Button>
<Button variant="secondary" type="reset"
onClick={handleClose}>Close</Button>
</Modal.Footer>

...

You can now try to login again. You can now login with user as the username with abcd1234 as
the password.

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

Connect to API
Hence, you need to learn how the Front-end Development connecting to the backend. And keep
the token to let the SPA identified that you have login. Now, let’s try to use the fake API to login
and get the token. (https://dummyjson.com)

If you need to keep the API domain name in a separated code, you can create a new file in
common with the code below:

export const userAPI = {


uri: "https://dummyjson.com"
}

Update the logic in the Login checking

...

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {


e.preventDefault();
schema.validate(formData, { abortEarly: false })
.then(() => {

fetch(`${userAPI.uri}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username: formData.username, password:
formData.password })
}).then((response) => {
if(response.ok) {
response.json().then((data) => {
localStorage.setItem('userInfo',
JSON.stringify(data.token));
setUserInfo({ firstname: data.firstName, lastname:
data.lastName});
setIsLoggedIn(true);
handleClose();
setErrors({});
})
} else {
setLoginError(`(${response.status}) Invalid username or
password`);
}
}).catch((error) => {
setLoginError(`(${error.status}) An error occurred. Please try
again later.`);
})
})

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

.catch((err)=> {
const validationErrors: { [key: string]: string } = {};
err.inner.forEach((error) => {
validationErrors[error.path] = error.message;
});
setErrors(validationErrors);
})

Try to test your app, with opening the storage in your browser (Application > Storage > Local
Storage) to see how the token store in your browser:

React Hook
React hooks are functions that enable functional components to use state and lifecycle features
that were previously only available in class components. You may find that in the Login example,
you can handle the change of component layout with the change of the status in your
application.

In Login example, we import the useState hook from the 'react' library. The useState function
returns an array with two elements: the current state value (isLoggedIn) and a function
(setIsLoggedIn) to update it. We initialize with false, and change the true once the login progress
is successfully completed.

The useEffect hook is used to perform side effects in your functional components, such as
fetching data, subscribing to external events, or manually changing the DOM. It combines the
functionality of componentDidMount, componentDidUpdate, and componentWillUnmount in
class components. In our case, if the JSON is retrieve from API, you need to update the data and
display on screen once. This will try more detail in next tutorial.

Also, useContext can also be applied but here we keep it simple first.

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]
IT524048Q Full Stack Development
Worksheet 5

HTML Web Storage


With web storage, web applications can store data locally within the user's browser.

Before HTML5, application data had to be stored in cookies, included in every server request.
Web storage is more secure, and large amounts of data can be stored locally, without affecting
website performance.

Unlike cookies, the storage limit is far larger (at least 5MB) and information is never transferred
to the server.

Web storage is per origin (per domain and protocol). All pages, from one origin, can store and
access the same data.

In the example, we store the token once the login returns an access-key and it can make use with
the other components within the application for authorized login. We can reset the record once
user logout to the application.

Worksheet Tasks
Try to understand the Dummy API and display the user first name and last name once login as
below.

Copyright to Hong Kong Institute of Information Technology


This document is for HKIIT students for their own use in completing their learning for this module
and should not be passed to third parties or posted on any website. Any infringements of this
rule should be reported to [email protected]

You might also like