React: how to use the useContext hook in combination with the useReducer and firebase for user authentification

Let's get started

yarn add firebase
REACT_APP_API_KEY=
REACT_APP_AUTH_DOMAIN=
REACT_APP_DATABASE_URL=
REACT_APP_PROJECT_ID=
REACT_APP_STORAGE_BUCKET=
REACT_APP_MESSAGING_SENDER_ID=
REACT_APP_APP_ID=
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/auth";
import "firebase/storage";

const firebaseConfig = {
apiKey: process.env.REACT_APP_API_KEY,
authDomain: process.env.REACT_APP_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_DATABASE_URL,
projectId: process.env.REACT_APP_PROJECT_ID,
storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
};

firebase.initializeApp(firebaseConfig);

export const auth = firebase.auth();
export const storage = firebase.storage();
export const firestore = firebase.firestore();

const value = useContext(MyContext);

Accepts a context object (the value returned from React.createContext) and returns the current context value for that context. The current context value is determined by the value prop of the nearest <MyContext.Provider> above the calling component in the tree.

When the nearest <MyContext.Provider> above the component updates, this Hook will trigger a rerender with the latest context value passed to that MyContext provider. Even if an ancestor uses React.memo or shouldComponentUpdate, a rerender will still happen starting at the component itself using useContext.

Don’t forget that the argument to useContext must be the context object itself:

Correct: useContext(MyContext)

Incorrect: useContext(MyContext.Consumer)

Incorrect: useContext(MyContext.Provider)

const [state, dispatch] = useReducer(reducer, initialArg, init);

An alternative to useState. Accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method. (If you’re familiar with Redux, you already know how this works.)

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. useReducer also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks.

const authReducer = (state, action) => {
switch (action.type) {
case 'REGISTER':
return {...state, account: action.payload.account, profile: action.payload.profile}
case 'LOGIN':
return {...state, account: action.payload.account, profile: action.payload.profile}
case 'UPDATE_PROFILE':
return {...state, profile: action.payload.profile}
case 'UPDATE_ACCOUNT':
return {...state, account: action.payload.account}
case 'LOGOUT':
return {...state, account: {}, profile: {}}
case 'ERROR':
return {...state, errors: action.payload.errors}
default: {
throw new Error(`Unhandled action type: ${action.type}`)
}
}
}
const initialState = {
account: {},
profile: {},
errors: [],
}
const AuthContext = React.createContext(initialState)
const AuthProvider = ({children}) => {
const [state, dispatch] = React.useReducer(authReducer, initialState)
const value = {state, dispatch}


return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
)
}

export {AuthContext, AuthProvider}
import React from 'react';
import ReactDOM from 'react-dom';
import {ModalProvider} from "./providers/modalProvider";
import App from "./App";
import {AuthProvider} from "./providers/authProvider";

ReactDOM.render(
<React.StrictMode>
<AuthProvider>
<App/>
</AuthProvider>
</React.StrictMode>,
document.getElementById('root')
);
const {state, dispatch} = React.useContext(AuthContext)
onClick={() => {
dispatch({type: 'LOGOUT'})
}
import React from 'react'

/* REDUCER */
const
initialState = {
account: {},
profile: {},
errors: [],
}

const authReducer = (state, action) => {
switch (action.type) {
case 'REGISTER':
return {...state, account: action.payload.account, profile: action.payload.profile}
case 'LOGIN':
return {...state, account: action.payload.account, profile: action.payload.profile}
case 'UPDATE_PROFILE':
return {...state, profile: action.payload.profile}
case 'UPDATE_ACCOUNT':
return {...state, account: action.payload.account}
case 'LOGOUT':
return {...state, account: {}, profile: {}}
case 'ERROR':
return {...state, errors: action.payload.errors}
default: {
throw new Error(`Unhandled action type: ${action.type}`)
}
}
}

/* COMPONENT */
const
AuthContext = React.createContext(initialState)

const AuthProvider = ({children}) => {
const [state, dispatch] = React.useReducer(authReducer, initialState)
const value = {state, dispatch}

return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
)
}

export {AuthContext, AuthProvider}

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store