Frontend Serverless with React and GraphQL
Start at the beginning and work your way through this project. The code for each step as well as the finished project can be found in the Github repository.
22. Add useFetchUser Hook
Objective: Create a useFetchUser hook that will allow us to determine user state within react components.
The hook works by having an internal state that is set by looking at the __user
object that is saved to the window
object. Initially, that __user
object is not present so we can use an effect to call the fetchUser
function which will fetch the current user from the /api/me
api endpoint. We will receive json back and we save that to window.__user
.
This example has been adapted from the same official Auth0 repository example application for a (Next.js application)[https://github.com/zeit/next.js/tree/master/examples/auth0] that we used in the previous step.
utils/user.ts
import { useState, useEffect } from 'react';import fetch from 'isomorphic-unfetch';interface MyWindow extends Window {__user: any;}declare var window: MyWindow;export async function fetchUser(cookie = '') {if (typeof window !== 'undefined' && window.__user) {return window.__user;}const res = await fetch('/api/me',cookie? {headers: {cookie,},}: {},);if (!res.ok) {delete window.__user;return null;}const json = await res.json();if (typeof window !== 'undefined') {window.__user = json;}return json;}export function useFetchUser({ required } = {}) {const [loading, setLoading] = useState(() => !(typeof window !== 'undefined' && window.__user),);const [user, setUser] = useState(() => {if (typeof window === 'undefined') {return null;}return window.__user || null;});useEffect(() => {if (!loading && user) {return;}setLoading(true);let isMounted = true;fetchUser().then((user) => {// Only set the user if the component is still mountedif (isMounted) {// When the user is not logged in but login is requiredif (required && !user) {window.location.href = '/api/login';return;}setUser(user);setLoading(false);}});return () => {isMounted = false;};},// eslint-disable-next-line react-hooks/exhaustive-deps[],);return { user, loading };}