我们有一个简单的设置,涉及上下文API提供商包装 _APP.TSX
页面。我们正在尝试实现的流量是:
- 在页面上,我们使用
getserversideprops
我们从API收集一些数据,
- 我们通过道具将数据发送到页面,
- 我们从页面上更新上下文(上下文提供者正在包装
_APP.TSX
,如上所述)
- 上下文已更新,所有子女组件都可以访问其中的数据,
因此我们有一个非常标准的设置,可以在客户端端正确工作。问题在于,更新的上下文值没有用于SSR页面。
上下文API
const ContextValue = createContext();
const ContextUpdate = createContext();
export const ContextProvider = ({children}) => {
const [context, setContext] = useState({});
return <ContextValue.Provider value={context}>
<ContextUpdate.Provider value={setContext}>
{children}
</ContextValue.Provider>
</ContextUpdate.Provider>
}
export const useContextValue = () => {
const context = useContext(ContextValue);
return context;
}
export const useContextUpdate = () => {
const update = useContext(ContextUpdate);
return update;
}
然后我们在 _App.jsx
上都有上下文:
...
return <ContextProvider>
<ContextApiConsumingComponent />
<Component {...pageProps} />
</Context>
在任何页面中,如果我们可以使用上面提供的钩子更新上下文。例如:
export function Index({customData, isSSR}) {
const update = useContextUpdate();
if(isSSR) {
update({customData})
}
return (
<div>...</div>
);
}
export async function getServerSideProps(context) {
...
return {
props: { customData , isSSR}
};
};
我们可以在 contextapiconsumingcomponent
中消耗上下文:(
export function ContextApiConsumingComponent() {
const context = useContextValue()
return <pre>{JSON.stringify(context?.customData ?? {})}</pre>
}
非常简化的)代码在客户端上工作正常。但是在SSR期间,如果我们检查服务器发送给浏览器的HTML,我们会注意到&lt; pre&gt;&lt;/pre&gt;
标记即使上下文值正确,发送到 __ next_data __
脚本部分中的浏览器(加载应用程序后,它们精确地填充了浏览器上的数据)。
我将 github repo 也有最低的再现。
我想念什么吗?
We have a simple setup involving a Context API provider wrapping the _app.tsx
page. The flow we're trying to implement is:
- On a page we collect some data from an API by using
getServerSideProps
- We send the data to the page through the props
- We update the context from the page (the context provider is wrapping the
_app.tsx
as mentioned above)
- The context is updated and all the children components can access the data in it
So we have a pretty standard setup that works correctly on the client side. The problem is that the updated context values are not being used to SSR the pages.
Context API
const ContextValue = createContext();
const ContextUpdate = createContext();
export const ContextProvider = ({children}) => {
const [context, setContext] = useState({});
return <ContextValue.Provider value={context}>
<ContextUpdate.Provider value={setContext}>
{children}
</ContextValue.Provider>
</ContextUpdate.Provider>
}
export const useContextValue = () => {
const context = useContext(ContextValue);
return context;
}
export const useContextUpdate = () => {
const update = useContext(ContextUpdate);
return update;
}
Then we have on _app.jsx
:
...
return <ContextProvider>
<ContextApiConsumingComponent />
<Component {...pageProps} />
</Context>
And in any page, if we can update the context by using the hook provided above. For example:
export function Index({customData, isSSR}) {
const update = useContextUpdate();
if(isSSR) {
update({customData})
}
return (
<div>...</div>
);
}
export async function getServerSideProps(context) {
...
return {
props: { customData , isSSR}
};
};
And we can consume the context in our ContextApiConsumingComponent
:
export function ContextApiConsumingComponent() {
const context = useContextValue()
return <pre>{JSON.stringify(context?.customData ?? {})}</pre>
}
The (very simplified) code above works fine on the client. But during the SSR, if we inspect the HTML sent to the browser by the server, we'll notice that the <pre></pre>
tags are empty even though the context values are correctly sent to the browser in the __NEXT_DATA__
script section (they are precisely filled with the data on the browser after the app is loaded).
I've put together a GitHub repo with a minimum reproduction too.
Am I missing something?
发布评论
评论(2)
据我所知,React不等待在SSR期间执行异步动作。而SetState是一个异步操作。
如果您希望在SSR期间对其进行渲染,则需要为 initialValue “> usestate 钩子。
As far as I understand, React doesn't wait for asynchronous actions to be performed during the SSR. Whereas setState is an asynchronous operation.
If you want it to be rendered during SSR, you need to provide an
initialValue
for useState hook.不确定是否有其他原因使用上下文将此数据获取到API消费者中,但是使用NextJ,
getStaticProps
或getserversideprops
当然要馈入路由组件,但是也许您错过了以下细节?https://nextjs.org/docs/advanced-fanced-features/custom-custom-app
因此,
_app.tsx
可以在您的路由组件中采取任何行动,通常会从getStaticProps
或getServersideProps
types.ts
pages/_app.tsx
pages/somepage.tsx
Not sure if you have other reasons for using the context to get this data into the api consumer but with nextjs, the
getStaticProps
orgetServerSideProps
of course feeds into the route component, but maybe you've missed the following detail?https://nextjs.org/docs/advanced-features/custom-app
Therefore the
_app.tsx
can act on any props your route components would normally receive fromgetStaticProps
orgetServerSideProps
types.ts
pages/_app.tsx
pages/somepage.tsx