T5 - State Hook and Localstorage
T5 - State Hook and Localstorage
Worksheet 5
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.
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.
npm i bootstrap
Open index.html and update the script to adopt Bootstrap to the application as below
React Form
In previous worksheet, you should already familiarizing the conditional rendering. Now, let’s
have some modification to work with the login.
interface LoginForm {
username: string;
password: string;
}
if(isLoggedIn) {
return(
<>
Remember to update App.tsx so you can make use with the new Login component.
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.
interface LoginForm {
username: string;
password: string;
}
handleClose();
setErrors({});
})
.catch((err) => {
const validationErrors: { [key: string]: string } = {};
err.inner.forEach((error) => {
validationErrors[error.path] = error.message;
});
setErrors(validationErrors);
});
};
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>
</Form>
</Modal>
</>
);
}
};
You can now try to login. You can find that the username and password is now show up in the
browser console.
...
...
});
};
...
<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.
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:
...
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.`);
})
})
.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.
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.