Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Exposing every component in Next.js app to custom hook on pageLoad

in my Next.js app, I have a react hook that fetches the currently authenticated user, and sets it to a piece of global state. I want to run this hook once on page load, but I want it to be exposed to every component in the app

import { useState, useEffect } from 'react';
import { useQuery } from '@apollo/client';
import { GET_AUTHED_USER } from '../utils/queries';
import { useAppContext } from '../context';

export const getCurrentUser = () => {
    const [isCompleted, setIsCompleted] = useState(false)

    const [state, setState] = useAppContext()

    const { data: authedUserData } = useQuery(GET_AUTHED_USER, {
        onCompleted: () => setIsCompleted(true)
    });

    useEffect(() => {
        Router.push('/home')
        if (isCompleted) {
            setState({
                currentUser: authedUserData?.getAuthedUser,
                isAuthed: true,
            });
        }
    }, [isCompleted]);

    return [state, setState];

_APP.js

import '../styles/reset.css'
import { AppWrapper } from '../context'
import { getCurrentUser } from '../hooks';


function MyApp({ Component, pageProps }) {
  const [state] = getCurrentUser()

  console.log(state) // TypeError: Invalid attempt to destructure non-iterable instance.

  return (
    <AppWrapper>
      <Component {...pageProps} />
    </AppWrapper>
  )
}


export default MyApp

the hook does work in pages/index.js but that means I can only run it if the / endpoint is hit.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

<AppWrapper/> is where all the values get originally defined

import { createContext, useContext, useState } from 'react';
import { ApolloClient, InMemoryCache, ApolloProvider, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { getCookie } from '../utils/functions';


const AppContext = createContext();

export function AppWrapper({ children }) {

  const URI = 'http://localhost:5000/graphql';

  const [state, setState] = useState({
    currentUser: null,
    isAuthed: false,
  });

  const httpLink = createHttpLink({
    uri: URI,
  });

  const authLink = setContext((_, { headers }) => {
    // get the authentication token from local storage if it exists
    const token = getCookie('JWT');
    // return the headers to the context so httpLink can read them
    return {
      headers: {
        ...headers,
        authorization: token ? token : '',
      }
    }
  });

  const client = new ApolloClient({
    cache: new InMemoryCache(),
    link: authLink.concat(httpLink)
  });


  return (
    <AppContext.Provider value={[state, setState]}>
      <ApolloProvider client={client}>
        {children}
      </ApolloProvider>
    </AppContext.Provider>
  );
}


export function useAppContext() {
  return useContext(AppContext);
}

>Solution :

Interesting question, you want to load that portion of code only once per each browser hit?

Then the location is right. NextJs make sure when you have a unique browser hit, it runs _app.js, but only once, after that it’ll goes into a single page application mode.

After the above fact, actually whether a piece of code is run only once or twice or multiple time is mostly driven by how many times it detects the "change".

  useEffect(() => {
     // run
  }, [condition])

If the condition changes, it’ll run again. However if the condition does not change, but the whole piece is re-mount, it’ll run again. You have to consider both fact here.

In short, if you have to run it per route change, make the condition === route.name. A piece of advice, try work with the single page application first, then work with the unique feature nextJS, because otherwise it’ll be really difficult to figure out the answer.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading