OKay I’ll just need to make some quick notes with regards to login features of a website, and this is a rather new and elegant way of doing it.
Step 1: Decide on where in the component chain you’re going to implement login requirements.
In my case, it’s App.js, because everything else within the app is supposed to be ‘private’ and an individual’s views of their own portfolio.
Step 2: Create a login page.
I’ve used the stock one from material UI, which looks great. First, create a login.js component. Paste the content from this template into the component.
Step 3: Within App.js, import Login component, and conditionally render it if token is not set.
This will ensure that none of the other components in your App are rendered if the token is not set. E.g. if you go /streams or /trades, it’ll auto redirect to Login page.
| |
Step 4: Backend API Config
Most likely, you would have configured a backend login API POST route that would receive a username and a password, and return a token. In my case, if I make a POST request to localhost:3003/api/login, I’ll receive a token if login is valid. The token corresponds to the userId.
Step 5: Pass setToken props into Login component, and specify the props types as function
| |
Step 6: Make the form controlled with state hooks
| |
Step 7: Make a POST request with the data
In my case, I want the data to be sent to ’localhost:3003/api/login’ onSubmit. So, I will be coding the POST request within the handleSubmit button of login.js.
| |
In my case, the form uses FormData to get the data of the form, which I can access with data.get('email') etc.
Previously, the way I send data to any api is to set a dispatch(), with an action creator. The action creator will trigger a call to API via axios, and at the same time update the store. In this case, I don’t need to update the store - a simple call to API via axios seems to be fine.
Within my login.js, I imported axios, and set the login URL:
| |
The actual call should look something like this:
| |
And then I will simply call newLogin(loginCredentials), where loginCredentials is defined in event handler. The entire event handler now looks like this:
| |
Hopefully at this point, I would have access to the variable token, which stores the token of my login.
Finally, this is the crucial part. I call setToken(token). Recall that the login component has a prop called setToken, which is a function defined in App.js. As of yet, we have not defined setToken, but it should look something like this eventually.
| |
Notice that we conditionally return a Login component with the setToken as a callback prop, which, upon fulfilment with a token, sets the sessionStorage as the userToken.
Step 8: Implementing sessionStorage
In short, sessionStorage allows us to access the token even after a refresh of the page but not when we open a new tab or window; localstorage allows us to access the token even after we close the window, until we set a designated token expiry limit.
Implement SessionStorage by defining two functions (getToken and setToken) in app.js, calling one of them getToken() immediately upon entering component body, and the other one sent as props to Login component.
App.js:
| |
setToken is passed into Login component as callback prop (a kind of functional prop like handleClick that is only fulfilled upon receiving data in the children component), whereas getToken, below:
| |
Short sequence of events: When App component is rendered, it calls getToken(). If it is stored in sessionStorage, a token will be returned. If not, it will be empty. If token is not set, we render Login page. After we key in data, the Login page will send an Axios request to login API, and upon submit, will invoke the setToken prop, which will invoke a call within App.js, and set the sessionStorage as token value. Then, on App component render again, getToken() will call and set the token, and the rest of the components will render with the supplied token.
Sidenote: The optional chaining operator (?) is used because on first access, the token is undefined and when you access the property, you would generate an error. This is a more elegant solution to ‘getting past the first render problem’.
However, when you click submit, React does not bring you out of the login page. This is because React doesn’t have a statehook that causes rerender of the page.
Step 9: Creating a hook for token to cause rerender.
You’ll need to refactor your app to make use of the state hook. Create useToken.js.
useToken.js:
| |
Within App.js, change it to:
app.js:
| |
What’s happening is this. useToken() is a function that returns an object with two properties: setToken and token. When the app is first rendered, it creates two variables on line 8 of above. Line 8 does quite a few things.
First, it tries to getToken.
token = useToken().token will first trigger useToken() which will trigger useState(getToken()), which in turn trigers getToken() which looks for token within sessionStorage and returns if there is. If not, it returns null. On first render, this will be null. Hence, token is undefined.
Then, it makes available a setToken function, via useToken().setToken. When we call setToken(token) later via callback within Login prop, it’ll set sessionStorage.
Third, login page is rendered if token is not set. Within the page, we make a POST request to Axios which calls setToken(token). setToken() is called within App.js, setting the sessionStorage.