是否可以防止 getServerSideProps 在初始加载后导致整个页面重新加载?
Is it possible to prevent getServerSideProps causing a full page reload after initial load?
我有一个服务器呈现的 next.js 应用程序,它是一个 3 页结帐流程。在第一页,我正在获取各种设置数据,例如 getServerSideProps
内的标签翻译和购物篮项目,如下所示:
UserDetails.js
import React from 'react';
import { LabelsContext } from "../contexts";
import { Component1, Component2 } from '../components'
const UserDetails = () => {
const labels = useContext(LabelsContext);
return (
<div>
<Component1 labels={labels} />
<Component2 labels={labels} />
</div>
)
}
export const getServerSideProps = async (context) => {
const {
locale,
basketId,
} = context.res.locals;
const { cookie } = context.req.headers;
const graphQLClient = new GraphQLClient(
GRAPHQL_ENDPOINT,
{
headers: {
'Content-Language': locale,
'X-Basket': basketId,
cookie,
},
},
);
const { labels } = await graphQLClient.request(getLabels);
return {
labels,
locale,
};
};
export default UserDetails;
此数据随后从 pageProps
传递到 _app.js
中的本地状态,并从那里传递到上下文提供者:
_app.js
import React from 'react';
import { useApollo } from '@apollo/client';
const App = ({ Component, pageProps }) => {
const [labels, setLabels] = useState(pageProps.labels);
const apolloClient = useApollo(pageProps.initialApolloState);
return (
<ApolloProvider client={apolloClient}>
<LabelsContext.Provider value={labels}>
<Component {...pageProps} />
</LabelsContext.Provider>
</ApolloProvider>
);
};
这在初始呈现上运行良好,因为提取成功并且数据设置为 _app.js
状态意味着它们可用于流中的后续页面。但我的问题是,当用户单击浏览器后退按钮从第 2 页返回到 UserDetails 页面时,它会再次执行完整页面重新加载以重新获取数据。重新获取数据不是大问题,但是当页面重新加载时,在表单中输入的所有数据都会丢失。此外,当所有其他页面转换都是活泼的客户端加载时,用户体验有点不和谐。
在这种情况下,一旦页面已经加载一次,是否有办法防止重新加载整个页面?
谢谢大家
整个页面重新加载是因为在客户端转换期间检索 UserDetails
页面的 JSON 数据的请求失败。
在您的 next.config.js
中添加 assetPrefix
条目将产生以下效果:
Next.js will automatically use your asset prefix for the JavaScript and CSS files it loads from the /_next/
path.
但是,当在客户端上检索 JSON 数据时,资产前缀 不会 影响来自 getServerSideProps
的 /_next/data/
请求,这意味着这些请求将 404,这反过来会触发整个页面重新加载(如您所见)。
解决方案是使用 basePath
而不是 assetPrefix
。这允许您为整个应用程序设置路径前缀,其中包括 getServerSideProps
为页面检索 JSON 数据的请求。
目前,除了使用 basePath
之外别无选择,因为这是向 /_next/data/
请求添加前缀的唯一方法。但是,有一个关于这个问题的公开讨论:https://github.com/vercel/next.js/discussions/25681.
我有一个服务器呈现的 next.js 应用程序,它是一个 3 页结帐流程。在第一页,我正在获取各种设置数据,例如 getServerSideProps
内的标签翻译和购物篮项目,如下所示:
UserDetails.js
import React from 'react';
import { LabelsContext } from "../contexts";
import { Component1, Component2 } from '../components'
const UserDetails = () => {
const labels = useContext(LabelsContext);
return (
<div>
<Component1 labels={labels} />
<Component2 labels={labels} />
</div>
)
}
export const getServerSideProps = async (context) => {
const {
locale,
basketId,
} = context.res.locals;
const { cookie } = context.req.headers;
const graphQLClient = new GraphQLClient(
GRAPHQL_ENDPOINT,
{
headers: {
'Content-Language': locale,
'X-Basket': basketId,
cookie,
},
},
);
const { labels } = await graphQLClient.request(getLabels);
return {
labels,
locale,
};
};
export default UserDetails;
此数据随后从 pageProps
传递到 _app.js
中的本地状态,并从那里传递到上下文提供者:
_app.js
import React from 'react';
import { useApollo } from '@apollo/client';
const App = ({ Component, pageProps }) => {
const [labels, setLabels] = useState(pageProps.labels);
const apolloClient = useApollo(pageProps.initialApolloState);
return (
<ApolloProvider client={apolloClient}>
<LabelsContext.Provider value={labels}>
<Component {...pageProps} />
</LabelsContext.Provider>
</ApolloProvider>
);
};
这在初始呈现上运行良好,因为提取成功并且数据设置为 _app.js
状态意味着它们可用于流中的后续页面。但我的问题是,当用户单击浏览器后退按钮从第 2 页返回到 UserDetails 页面时,它会再次执行完整页面重新加载以重新获取数据。重新获取数据不是大问题,但是当页面重新加载时,在表单中输入的所有数据都会丢失。此外,当所有其他页面转换都是活泼的客户端加载时,用户体验有点不和谐。
在这种情况下,一旦页面已经加载一次,是否有办法防止重新加载整个页面?
谢谢大家
整个页面重新加载是因为在客户端转换期间检索 UserDetails
页面的 JSON 数据的请求失败。
在您的 next.config.js
中添加 assetPrefix
条目将产生以下效果:
Next.js will automatically use your asset prefix for the JavaScript and CSS files it loads from the
/_next/
path.
但是,当在客户端上检索 JSON 数据时,资产前缀 不会 影响来自 getServerSideProps
的 /_next/data/
请求,这意味着这些请求将 404,这反过来会触发整个页面重新加载(如您所见)。
解决方案是使用 basePath
而不是 assetPrefix
。这允许您为整个应用程序设置路径前缀,其中包括 getServerSideProps
为页面检索 JSON 数据的请求。
目前,除了使用 basePath
之外别无选择,因为这是向 /_next/data/
请求添加前缀的唯一方法。但是,有一个关于这个问题的公开讨论:https://github.com/vercel/next.js/discussions/25681.