将 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
,否则很难找到答案。
在我的 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
,否则很难找到答案。