When using Material UI hooks with NextJS and react-apollo-hooks, received bug - TypeError: Cannot read property 'theme' of undefined
at MyDocument.render (/material-ui/examples/nextjs-hooks-with-typescript/.next/server/static/development/pages/_document.js:156:38)
Able to use Material UI hooks and Apollo hooks together.
undefined pageContext caused TypeError: Cannot read property 'theme' of undefined at line:
https://github.com/ivawzh/material-ui/blob/fc6ae01e66bde4252a08903719a59ef108e05e5f/examples/nextjs-hooks-with-typescript/pages/_document.tsx#L14

I have prepared a repo here https://github.com/ivawzh/material-ui/commit/fc6ae01e66bde4252a08903719a59ef108e05e5f
Steps:
git clone [email protected]:ivawzh/material-ui.gitcd material-ui/examples/nextjs-hooks-with-typescriptnpm install && npm run devhttp://localhost:3000/countries2I am trying to use Apollo hooks with Material UI hooks example.
From the repo above you will see the non-hook Apollo endpoint at http://localhost:3000/countries is working fine as expected. But when Apollo hooks is in used, app will crash because pageContext becomes undefined.
| Tech | Version |
|--------------|---------|
| Material-UI | v3.8.1 |
| React | 16.7.0-alpha.2 |
| Browser | Chrome |
| TypeScript | 3.2.2 |
| react-apollo | 2.3.3 |
| react-apollo-hooks | 0.2.1 |
Could you humor me and do a yarn list hoist-non-react-statics where the example is installed and post the resutls?
Sure.
โ nextjs-hooks-with-typescript git:(nextjs-apollo-hooks) yarn list hoist-non-react-statics
yarn list v1.9.4
warning Filtering by arguments is deprecated. Please use the pattern option instead.
โโ @material-ui/[email protected]
โ โโ [email protected]
โโ [email protected]
โโ [email protected]
โโ [email protected]
โจ Done in 0.41s.
Update
Also did yarn add [email protected] just for fun.
After that, bug still persists and yarn list looks like this
โ nextjs-hooks-with-typescript git:(nextjs-apollo-hooks) โ yarn list hoist-non-react-statics
yarn list v1.9.4
warning Filtering by arguments is deprecated. Please use the pattern option instead.
โโ [email protected]
โโ [email protected]
โ โโ [email protected]
โโ [email protected]
โโ [email protected]
โจ Done in 0.41s.
@ivawzh This is an integration issue with Apollo. I'm not sure it's the right place to open an issue. It would suggest we move the issue to stackoverflow.
@oliviertassinari right. will do.
I think the examples are here to provide seamless integration with the other popular libs like NextJs or Apollo. And the error trace is pointing to the static _document file from the code written by Material UI example. Which suggests the example is less extensible than I hope it is. So that I opened a ticket here.
Anyway, just created an stackoverflow question here https://stackoverflow.com/questions/54155865/bug-on-integrating-material-ui-hooks-and-apollo-hooks
Appreciated your helps ๐
@ivawzh I'm personally using Next.js + Apollo + Material-UI at https://www.onepixel.com/. Now, there is one important difference. We are not using the _app.js capability as in the example on the Material-UI repository, at least not yet. We are also not using next-with-apollo, we are using something custom (Apollo is a performance killer on the server, the cache is slow, the DOM tree traversal is extremely slow, the query formatting is slow, to mitigate the issue, we conditionally disable getDataFromTree in the pages). I will give a second look at the problem.
@oliviertassinari Heaps of thanks! That is some super useful information. I will also reconsider using Apollo on SSR if perf is so bad.
Is there any chance that you have some public available example of the setup you mentioned or maybe blog about the perf/benchmark and mitigation?
@ivawzh If you move the server-side queries to get getIntialProps, it's not great but doable. Google Crawler stats are around 300ms of latency on our website (we index millions of pages). Ideally, we would like to see 100ms, it's important for websites relying on SEO with a lot a lot a lot of pages. The DX is awesome, I think that it worth the tradeoff. I have nothing public if not the examples we have here.
@ivawzh We are introducing a server-side rendering API: #15030. You can apply the same pattern now:
--- a/examples/nextjs-hooks-with-typescript/pages/_app.tsx
+++ b/examples/nextjs-hooks-with-typescript/pages/_app.tsx
@@ -39,12 +39,6 @@ class MyApp extends App <Props> {
<Head>
<title>My page</title>
</Head>
- {/* Wrap every page in Styles and Theme providers */}
- <StylesProvider
- generateClassName={this.pageContext.generateClassName}
- sheetsRegistry={this.pageContext.sheetsRegistry}
- sheetsManager={this.pageContext.sheetsManager}
- >
{/* ThemeProvider makes the theme available down the React
tree thanks to React context. */}
<ThemeProvider theme={this.pageContext.theme}>
@@ -54,7 +48,6 @@ class MyApp extends App <Props> {
to render collected styles on server side. */}
<Component pageContext={this.pageContext} {...pageProps} />
</ThemeProvider>
- </StylesProvider>
</ApolloHooksProvider>
</ApolloProvider>
</Container>
diff --git a/examples/nextjs-hooks-with-typescript/pages/_document.tsx b/examples/nextjs-hooks-with-typescript/pages/_document.tsx
index bb5ddad8c..a37a6f1bd 100644
--- a/examples/nextjs-hooks-with-typescript/pages/_document.tsx
+++ b/examples/nextjs-hooks-with-typescript/pages/_document.tsx
@@ -2,7 +2,8 @@ import { MuiThemeProviderProps } from '@material-ui/core/styles/MuiThemeProvider
import Document, { AnyPageProps, Head, Main, NextScript, PageProps } from 'next/document';
import React, { ComponentType } from 'react';
import flush from 'styled-jsx/server';
-import { PageContext } from '../src/getPageContext';
+import getPageContext, { PageContext } from '../src/getPageContext';
+import { StylesProvider, ThemeProvider } from '@material-ui/styles';
class MyDocument extends Document<{
pageContext: MuiThemeProviderProps;
@@ -43,7 +44,7 @@ interface PagePropsWithPageContext extends AnyPageProps {
pageContext: PageContext;
}
-MyDocument.getInitialProps = ctx => {
+MyDocument.getInitialProps = async ctx => {
// Resolution order
//
// On the server:
@@ -66,16 +67,17 @@ MyDocument.getInitialProps = ctx => {
// 3. app.render
// 4. page.render
- // Render app and page and get the context of the page with collected side effects.
- let pageContext: PageContext | undefined;
- const page = ctx.renderPage((Component: ComponentType<PagePropsWithPageContext>) => {
- const WrappedComponent: ComponentType<{ pageContext: PageContext } & PageProps> = props => {
- pageContext = props.pageContext;
- return <Component {...props} />;
- };
+ const originalRenderPage = ctx.renderPage;
+ const pageContext = getPageContext();
- return WrappedComponent;
- });
+ ctx.renderPage = () =>
+ originalRenderPage({
+ enhanceApp: App => props => (<StylesProvider
+ sheetsRegistry={pageContext.sheetsRegistry}
+ sheetsManager={pageContext.sheetsManager}><App {...props} /></StylesProvider>),
+ });
+
+ const initialProps = await Document.getInitialProps(ctx);
let css;
// It might be undefined, e.g. after an error.
@@ -84,7 +86,7 @@ MyDocument.getInitialProps = ctx => {
}
return {
- ...page,
+ ...initialProps,
pageContext,
// Styles fragment is rendered after the app and page rendering finish.
styles: (
It fixes the problem on my end.
@oliviertassinari Compared to the now available nextjs-hooks-with-typescript example from december, beside the ones you posted are there any other changes in it? If yes, where can I find the updated example?
The next branch never had this example, and the base branch version never got this update.
@bozada You probably need this example: /examples/nextjs-next-with-typescript. It's TypeScript + Next.js + Material-UI v4 (with the new SSR API).
Most helpful comment
@ivawzh We are introducing a server-side rendering API: #15030. You can apply the same pattern now:
It fixes the problem on my end.