React State management using useContext and useReduce hooks with FaceIO face authentication.

John Thiong'o
6 min readSep 29, 2022

--

Hi there,

In this build I am going to show the use of the React Context API and the useReduce hook to manage state in a react application. To demonstrate this we will build a user authentication react component, taking advantage of the simple FaceIO face authentication system to authenticate our users. Once they are authenticated we will then pass the user data to the state and be able to consume it in other components.

Why we will use FaceIO.

FaceIO is a facial authentication system for websites and web based applications.

FaceIO is,

  1. Very easy to implement. It takes less than 3 lines of code and basically entails adding a script like the google gtag. For more you can check here.
  2. Seamless and does not entail the user getting FIDO keys, OTP codes and security questions thereby enhancing user experience in our site.
  3. Very secure. First it provides a defense level facial recognition accuracy ensuring that we accurately authenticate each and every user using their facial recognition engine. Secondly it guarantees the privacy of the user by ensuring that there data is safe and also that they don’t actually store the face of the user but rather a facial vector.

This is part two of a two part series if you would like to follow along part one is here.

We are going to pick up from where we left last time. Firstly we are going to arrange our content appropriately

In the src folder let us create a folder pages and in it create two files named Home.tsx and SignUp.tsx

Next we are going to add react router dom

So that your build should now look like this,

adding pages

We are going to transfer all the contents of App.tsx to the home page except the SignUpForm.

Import the signup component to the sign up page.

Let us now bring the react route dom into the App.tsx so that we are able to route to different pages of our app.

Since now we have finished the arrangement of our site let us get into the gist of our build.

We are going to create a login function to login through FaceIO (remember we had created a signup function in the previous part).

Then we are going to take the user data we get from FaceIO response and pass it into the state using useContext and useReducer.

Setting up useContext in React and Typescript.

Let us create a new folder in src folder named context and in there a file named StateProvider.tsx, in there we will make userContext provider.

Because we are using typescript we will need to provide types for our build,

in src/@types/user.d.ts we will create the userContext type.

So our createContext will be of type userContextType since when there will be no user the user will be null.

Now let create a folder helpers in src and in it a file named Reducers.ts

There is one type we did not define that is the action type let us update it accordingly

Go to src/@types/user.d.ts and add,

Now once we are done with this we can update StateProvider as this,

import React, { createContext, ReactNode, useReducer } from 'react';
import { userContextType } from '../@types/user';
import { initialState, reducer } from '../helpers/Reducers';
export const userContext = createContext<{
state: userContextType;
dispatch: React.Dispatch<any>;
}>({
state: initialState,
dispatch: () => null,
});
const StateProvider: React.FC<{ children: ReactNode }> = ({ children }) => {//bring the useReducer hook and feed it with the reducer function and the initial state
const [state, dispatch] = useReducer(reducer, initialState);
return (//update the value with the state and dispatch thus you are able to access this values in any component or page
<userContext.Provider value={{ state, dispatch }}>
{children}
</userContext.Provider>
);
};

Go to App.tsx import the StateProvider and wrap the entire build with it.

Let us now create a login component to be able to feed user data to the state.

In the folder componets create a file Login.tsx and in it create a login,

import { Link } from 'react-router-dom';const Login = () => {
return (
<div>
<h1 className='text-3xl font-bold text-blue-600 mb-4'>
Welcome, please login
</h1>
<button className='w-full p-3 bg-blue-700 rounded-md text-white text-sm mb-4'>
Login
</button>
<div>
<p>You don't have an account? Please sign-up.</p>
<Link to='/signup'>
<button className='w-full p-3 bg-white outline-blue-800 rounded-md text-blue-800 text-sm mb-4'>
Sign Up
</button>
</Link>
</div>
</div>
);
};
export default Login;

This component will be our gate guard that will refuse anyone admittance to our site unless they have loged in

So in our home component we will need to make some few changes.

We will query whether there is a user in the state that is if user is not null then we will show the home otherwise we will show
the login component.

This is how your page should look like by now,

login

Let us now go back to the login component and update the logic, that is call FaceIO and dispatch user data.

When we call FaceIO to authenticate (FaceIO authentication is documented here), and the authentication is successful we will receive a payload with the data the user provided when they signed up. That payload is what we are going to dispatch to the state.

import React, { useContext, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { userContext } from '../context/StateProvider';
import { actionTypes } from '../helpers/Reducers';
const Login = () => {
//we load faceIO using a useEffect hook
let faceio: any;
useEffect(() => {
faceio = new faceIO('fioa48b7');
}, []);
//we use a useContext hook dispatch to be able to dispatch our user to the state
const { dispatch } = useContext(userContext);
//we set up the handle login function
const handleLogin = async () => {
try {
let response = await faceio.authenticate({
locale: 'auto',
});
alert(`
You have been identified successfully
Unique Facial ID: ${response.facialId}
PayLoad: ${JSON.stringify(response.payload)}
`);
dispatch({ type: actionTypes.SET_USER, user: response.payload });alert('You have successfully logged in');
} catch (error) {
console.log(error);
alert('Failed to login, please refresh and try again');
}
};
return (
<div className='flex flex-col justify-center items-center'>
<h1 className='text-3xl font-bold text-blue-600 mb-4'>
Welcome, please login
</h1>
<button onClick={handleLogin} className='w-full p-3 bg-blue-700 rounded-md text-white text-sm mb-4'>
Login
</button>
<div>
<p>You don't have an account? Please sign-up.</p>
<Link to='/signup'>
<button

className='w-full p-3 bg-white outline-blue-800 rounded-md text-blue-800 text-sm mb-4'
>
Sign Up
</button>
</Link>
</div>
</div>
);
};
export default Login;

Once we are done with that our application is good and ready but let us add a welcome user statement in the home page.
Under the h1 tags add.

We are now done, if you were successful, and you try loging in you will see,

The whole of this build can be found in Github, while you are there please add a star to it.

For more on FaceIO

  1. The getting started guide.
  2. The integration guide.
  3. The Developer center.
  4. The frequently asked questions section.
  5. The trust center.

There are also some very interesting articles to get you on your way.

Login/Sign up form using FaceIO, Next.js and Tailwind CSS

Implementing facial authentication on a Vue.js app.

How to Authenticate a User with Face Recognition in React.js.

That is the conclusion for now but always check back for more content like this.

--

--