将 Next.js 应用程序中的每个组件公开到页面加载上的自定义挂钩

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

在我的 Next.js 应用程序中,我有一个反应挂钩,它获取当前经过身份验证的用户,并将其设置为一个全局状态。我想在页面加载时 运行 这个挂钩一次,但我希望它暴露给应用程序中的每个组件

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

挂钩在 pages/index.js 中确实有效,但这意味着如果 / 端点被命中,我只能 运行 它。

<AppWrapper/> 是所有值最初定义的地方

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);
}

有趣的问题,您想在每次浏览器点击时只加载该部分代码吗?

那么位置就对了。 NextJs 确保当您有一个独特的浏览器点击时,它 运行 是 _app.js,但只有一次,之后它将进入单页应用程序模式。

根据上述事实,实际上一段代码是 运行 一次、两次还是多次主要取决于它检测到“变化”的次数。

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

如果条件发生变化,它将再次 运行。但是,如果条件没有改变,但整块是re-mount,它会再次运行。你必须在这里考虑这两个事实。

简而言之,如果每次更改路线都必须 运行,请进行 condition === route.name。一个建议,先尝试使用单页应用程序,然后使用独特的功能 nextJS,否则很难找到答案。