Authentication Flow with useReducer
Implement an authentication flow, managing the state of user login, logout and token refresh logic with useReducer.
const initialState = {
isAuthenticated: false,
user: null,
token: null,
isLoading: false
};
const authReducer = (state, action) => {
switch (action.type) {
case 'REQUEST_LOGIN':
return {
...state,
isLoading: true
};
case 'LOGIN_SUCCESS':
return {
...state,
user: action.payload.user,
token: action.payload.token,
isAuthenticated: true,
isLoading: false
};
case 'LOGOUT':
return {
...state,
user: null,
token: null,
isAuthenticated: false,
isLoading: false
};
case 'LOGIN_ERROR':
return {
...state,
isLoading: false
};
case 'TOKEN_REFRESH':
return {
...state,
token: action.payload.token
};
default:
return state;
}
};
Defines initial state and a reducer to manage authentication states through different actions.
const login = async (dispatch, credentials) => {
dispatch({ type: 'REQUEST_LOGIN' });
try {
// Replace with your actual login API call
const response = await fakeAuthApi(credentials);
if (response.token) {
dispatch({ type: 'LOGIN_SUCCESS', payload: response });
// Save token to local storage or cookie
} else {
dispatch({ type: 'LOGIN_ERROR' });
}
} catch (error) {
dispatch({ type: 'LOGIN_ERROR' });
}
};
This function handles the logic for initiating a login request, processing a successful authentication or handling errors.
const logout = (dispatch) => {
dispatch({ type: 'LOGOUT' });
// Perform additional cleanup if needed
};
A function to handle user logout, dispatching an action to update the app state.
const refreshToken = async (dispatch, currentToken) => {
try {
// Replace with your actual token refresh API call
const newToken = await fakeRefreshTokenApi(currentToken);
dispatch({ type: 'TOKEN_REFRESH', payload: { token: newToken } });
} catch (error) {
dispatch({ type: 'LOGIN_ERROR' });
}
};
Function for refreshing the authentication token when it expires or is about to expire.
const App = () => {
const [state, dispatch] = React.useReducer(authReducer, initialState);
// Authentication context value
const authContextValue = useMemo(() => ({
state,
dispatch,
login: (credentials) => login(dispatch, credentials),
logout: () => logout(dispatch),
refreshToken: (currentToken) => refreshToken(dispatch, currentToken)
}), [state]);
// Example usage
// const { state, login, logout } = React.useContext(AuthContext);
// if (state.isAuthenticated) { /* Show user dashboard */ }
// else { /* Show login form */ }
return (
// Your app JSX goes here
);
};
The main App component where we make use of useReducer hook alongside context to manage authentication states and provide helper functions.
// Fake API functions for demonstration purposes
async function fakeAuthApi(credentials) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ user: 'John Doe', token: 'fake-jwt-token' })
}, 1000);
});
}
async function fakeRefreshTokenApi(currentToken) {
return new Promise((resolve) => {
setTimeout(() => {
resolve('fake-new-jwt-token');
}, 1000);
});
}
Fake API functions to simulate network requests for login and token refresh.