From ca33d9773581a8b0ff37c92260b48c9f72b42de9 Mon Sep 17 00:00:00 2001 From: NikitaVlaznev <nikita.dto@gmail.com> Date: Wed, 27 Jun 2018 23:30:40 +0300 Subject: [PATCH] [docs] Use _app.js instead of wrapping every page by withRoot() (#11989) * [examples] Avoid wrapping every page by withRoot * ready to be merged --- examples/nextjs/pages/_app.js | 51 +++++++++++++++++++++++++++ examples/nextjs/pages/_document.js | 47 ++++++++++++++----------- examples/nextjs/pages/about.js | 44 ++++++++++++++++++++++++ examples/nextjs/pages/index.js | 11 ++++-- examples/nextjs/src/withRoot.js | 55 ------------------------------ 5 files changed, 132 insertions(+), 76 deletions(-) create mode 100644 examples/nextjs/pages/_app.js create mode 100644 examples/nextjs/pages/about.js delete mode 100644 examples/nextjs/src/withRoot.js diff --git a/examples/nextjs/pages/_app.js b/examples/nextjs/pages/_app.js new file mode 100644 index 00000000000000..2ed955dde6d8fc --- /dev/null +++ b/examples/nextjs/pages/_app.js @@ -0,0 +1,51 @@ +import React from 'react'; +import App, { Container } from 'next/app'; +import { MuiThemeProvider } from '@material-ui/core/styles'; +import CssBaseline from '@material-ui/core/CssBaseline'; +import JssProvider from 'react-jss/lib/JssProvider'; +import getPageContext from '../src/getPageContext'; + +class MyApp extends App { + constructor(props) { + super(props); + this.pageContext = getPageContext(); + } + + pageContext = null; + + componentDidMount() { + // Remove the server-side injected CSS. + const jssStyles = document.querySelector('#jss-server-side'); + if (jssStyles && jssStyles.parentNode) { + jssStyles.parentNode.removeChild(jssStyles); + } + } + + render() { + const { Component, pageProps } = this.props; + return ( + <Container> + {/* Wrap every page in Jss and Theme providers */} + <JssProvider + registry={this.pageContext.sheetsRegistry} + generateClassName={this.pageContext.generateClassName} + > + {/* MuiThemeProvider makes the theme available down the React + tree thanks to React context. */} + <MuiThemeProvider + theme={this.pageContext.theme} + sheetsManager={this.pageContext.sheetsManager} + > + {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */} + <CssBaseline /> + {/* Pass pageContext to the _document though the renderPage enhancer + to render collected styles on server side. */} + <Component pageContext={this.pageContext} {...pageProps} /> + </MuiThemeProvider> + </JssProvider> + </Container> + ); + } +} + +export default MyApp; diff --git a/examples/nextjs/pages/_document.js b/examples/nextjs/pages/_document.js index 26203616889abc..a0c3cbb9af20b4 100644 --- a/examples/nextjs/pages/_document.js +++ b/examples/nextjs/pages/_document.js @@ -1,8 +1,7 @@ import React from 'react'; +import PropTypes from 'prop-types'; import Document, { Head, Main, NextScript } from 'next/document'; -import JssProvider from 'react-jss/lib/JssProvider'; import flush from 'styled-jsx/server'; -import getPageContext from '../src/getPageContext'; class MyDocument extends Document { render() { @@ -41,34 +40,44 @@ MyDocument.getInitialProps = ctx => { // Resolution order // // On the server: - // 1. page.getInitialProps - // 2. document.getInitialProps - // 3. page.render - // 4. document.render + // 1. app.getInitialProps + // 2. page.getInitialProps + // 3. document.getInitialProps + // 4. app.render + // 5. page.render + // 6. document.render // // On the server with error: - // 2. document.getInitialProps + // 1. document.getInitialProps + // 2. app.render // 3. page.render // 4. document.render // // On the client - // 1. page.getInitialProps - // 3. page.render + // 1. app.getInitialProps + // 2. page.getInitialProps + // 3. app.render + // 4. page.render + + // Render app and page and get the context of the page with collected side effects. + let pageContext; + const page = ctx.renderPage(Component => { + const WrappedComponent = props => { + pageContext = props.pageContext; + return <Component {...props} />; + }; + + WrappedComponent.propTypes = { + pageContext: PropTypes.object.isRequired, + }; - // Get the context of the page to collected side effects. - const pageContext = getPageContext(); - const page = ctx.renderPage(Component => props => ( - <JssProvider - registry={pageContext.sheetsRegistry} - generateClassName={pageContext.generateClassName} - > - <Component pageContext={pageContext} {...props} /> - </JssProvider> - )); + return WrappedComponent; + }); return { ...page, pageContext, + // Styles fragment is rendered after the app and page rendering finish. styles: ( <React.Fragment> <style diff --git a/examples/nextjs/pages/about.js b/examples/nextjs/pages/about.js new file mode 100644 index 00000000000000..611c4113904d51 --- /dev/null +++ b/examples/nextjs/pages/about.js @@ -0,0 +1,44 @@ +/* eslint-disable jsx-a11y/anchor-is-valid */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; +import { withStyles } from '@material-ui/core/styles'; +import Link from 'next/link'; + +const styles = theme => ({ + root: { + textAlign: 'center', + paddingTop: theme.spacing.unit * 20, + }, +}); + +function About(props) { + const { classes } = props; + + return ( + <div className={classes.root}> + <Typography variant="display1" gutterBottom> + Material-UI + </Typography> + <Typography variant="subheading" gutterBottom> + about page + </Typography> + <Typography gutterBottom> + <Link href="/"> + <a>Go to the main page</a> + </Link> + </Typography> + <Button variant="contained" color="primary"> + Do nothing button + </Button> + </div> + ); +} + +About.propTypes = { + classes: PropTypes.object.isRequired, +}; + +export default withStyles(styles)(About); diff --git a/examples/nextjs/pages/index.js b/examples/nextjs/pages/index.js index 34a48257b7de18..0ef5a8a6648d76 100644 --- a/examples/nextjs/pages/index.js +++ b/examples/nextjs/pages/index.js @@ -1,3 +1,5 @@ +/* eslint-disable jsx-a11y/anchor-is-valid */ + import React from 'react'; import PropTypes from 'prop-types'; import Button from '@material-ui/core/Button'; @@ -8,7 +10,7 @@ import DialogContentText from '@material-ui/core/DialogContentText'; import DialogActions from '@material-ui/core/DialogActions'; import Typography from '@material-ui/core/Typography'; import { withStyles } from '@material-ui/core/styles'; -import withRoot from '../src/withRoot'; +import Link from 'next/link'; const styles = theme => ({ root: { @@ -57,6 +59,11 @@ class Index extends React.Component { <Typography variant="subheading" gutterBottom> example project </Typography> + <Typography gutterBottom> + <Link href="/about"> + <a>Go to the about page</a> + </Link> + </Typography> <Button variant="contained" color="secondary" onClick={this.handleClick}> Super Secret Password </Button> @@ -69,4 +76,4 @@ Index.propTypes = { classes: PropTypes.object.isRequired, }; -export default withRoot(withStyles(styles)(Index)); +export default withStyles(styles)(Index); diff --git a/examples/nextjs/src/withRoot.js b/examples/nextjs/src/withRoot.js deleted file mode 100644 index 579b728752e038..00000000000000 --- a/examples/nextjs/src/withRoot.js +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { MuiThemeProvider } from '@material-ui/core/styles'; -import CssBaseline from '@material-ui/core/CssBaseline'; -import getPageContext from './getPageContext'; - -function withRoot(Component) { - class WithRoot extends React.Component { - pageContext = null; - - constructor(props) { - super(props); - - this.pageContext = this.props.pageContext || getPageContext(); - } - - componentDidMount() { - // Remove the server-side injected CSS. - const jssStyles = document.querySelector('#jss-server-side'); - if (jssStyles && jssStyles.parentNode) { - jssStyles.parentNode.removeChild(jssStyles); - } - } - - render() { - // MuiThemeProvider makes the theme available down the React tree thanks to React context. - return ( - <MuiThemeProvider - theme={this.pageContext.theme} - sheetsManager={this.pageContext.sheetsManager} - > - {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */} - <CssBaseline /> - <Component {...this.props} /> - </MuiThemeProvider> - ); - } - } - - WithRoot.propTypes = { - pageContext: PropTypes.object, - }; - - WithRoot.getInitialProps = ctx => { - if (Component.getInitialProps) { - return Component.getInitialProps(ctx); - } - - return {}; - }; - - return WithRoot; -} - -export default withRoot;