From 9445b615c996a6c4478e10262c08870672fde977 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Wed, 19 Dec 2018 19:58:57 +0100 Subject: [PATCH] [docs] Add a next.js demo with hooks (#13920) * [docs] Add a next.js demo with hooks * review --- examples/nextjs-hooks/.babelrc | 3 + examples/nextjs-hooks/.gitignore | 18 ++++ examples/nextjs-hooks/README.md | 22 +++++ examples/nextjs-hooks/next.config.js | 1 + examples/nextjs-hooks/package.json | 19 ++++ examples/nextjs-hooks/pages/_app.js | 52 +++++++++++ examples/nextjs-hooks/pages/_document.js | 99 +++++++++++++++++++++ examples/nextjs-hooks/pages/about.js | 40 +++++++++ examples/nextjs-hooks/pages/index.js | 64 +++++++++++++ examples/nextjs-hooks/src/bootstrap.js | 10 +++ examples/nextjs-hooks/src/getPageContext.js | 54 +++++++++++ examples/nextjs/pages/_app.js | 4 +- examples/nextjs/pages/_document.js | 13 ++- pages/_document.js | 2 +- 14 files changed, 396 insertions(+), 5 deletions(-) create mode 100644 examples/nextjs-hooks/.babelrc create mode 100644 examples/nextjs-hooks/.gitignore create mode 100644 examples/nextjs-hooks/README.md create mode 100644 examples/nextjs-hooks/next.config.js create mode 100644 examples/nextjs-hooks/package.json create mode 100644 examples/nextjs-hooks/pages/_app.js create mode 100644 examples/nextjs-hooks/pages/_document.js create mode 100644 examples/nextjs-hooks/pages/about.js create mode 100644 examples/nextjs-hooks/pages/index.js create mode 100644 examples/nextjs-hooks/src/bootstrap.js create mode 100644 examples/nextjs-hooks/src/getPageContext.js diff --git a/examples/nextjs-hooks/.babelrc b/examples/nextjs-hooks/.babelrc new file mode 100644 index 00000000000000..1ff94f7ed28e16 --- /dev/null +++ b/examples/nextjs-hooks/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["next/babel"] +} diff --git a/examples/nextjs-hooks/.gitignore b/examples/nextjs-hooks/.gitignore new file mode 100644 index 00000000000000..ed07c2acd4df3f --- /dev/null +++ b/examples/nextjs-hooks/.gitignore @@ -0,0 +1,18 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Next.js +/.next diff --git a/examples/nextjs-hooks/README.md b/examples/nextjs-hooks/README.md new file mode 100644 index 00000000000000..4c4cf72cae8d12 --- /dev/null +++ b/examples/nextjs-hooks/README.md @@ -0,0 +1,22 @@ +# Next.js Hooks example + +## How to use + +Download the example [or clone the repo](https://github.com/mui-org/material-ui): + +```bash +curl https://codeload.github.com/mui-org/material-ui/tar.gz/master | tar -xz --strip=2 material-ui-master/examples/nextjs +cd nextjs +``` + +Install it and run: + +```bash +npm install +npm run dev +``` + +## The idea behind the example + +[Next.js](https://github.com/zeit/next.js) is a framework for server-rendered React apps. +[Hooks](https://reactjs.org/docs/hooks-state.html) are an upcoming feature of React. diff --git a/examples/nextjs-hooks/next.config.js b/examples/nextjs-hooks/next.config.js new file mode 100644 index 00000000000000..f053ebf7976e37 --- /dev/null +++ b/examples/nextjs-hooks/next.config.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/examples/nextjs-hooks/package.json b/examples/nextjs-hooks/package.json new file mode 100644 index 00000000000000..b3e3ac98523158 --- /dev/null +++ b/examples/nextjs-hooks/package.json @@ -0,0 +1,19 @@ +{ + "name": "nextjs", + "version": "3.0.0", + "private": true, + "dependencies": { + "@material-ui/core": "latest", + "@material-ui/styles": "latest", + "jss": "latest", + "next": "latest", + "prop-types": "latest", + "react": "next", + "react-dom": "next" + }, + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + } +} diff --git a/examples/nextjs-hooks/pages/_app.js b/examples/nextjs-hooks/pages/_app.js new file mode 100644 index 00000000000000..afddb79255e846 --- /dev/null +++ b/examples/nextjs-hooks/pages/_app.js @@ -0,0 +1,52 @@ +import '../src/bootstrap'; +// --- Post bootstrap ----- +import React from 'react'; +import App, { Container } from 'next/app'; +import Head from 'next/head'; +import { StylesProvider, ThemeProvider } from '@material-ui/styles'; +import CssBaseline from '@material-ui/core/CssBaseline'; +import getPageContext from '../src/getPageContext'; + +class MyApp extends App { + constructor() { + super(); + this.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() { + const { Component, pageProps } = this.props; + return ( + + + My page + + {/* Wrap every page in Styles and Theme providers */} + + {/* ThemeProvider makes the theme available down the React + tree thanks to React context. */} + + {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */} + + {/* Pass pageContext to the _document though the renderPage enhancer + to render collected styles on server side. */} + + + + + ); + } +} + +export default MyApp; diff --git a/examples/nextjs-hooks/pages/_document.js b/examples/nextjs-hooks/pages/_document.js new file mode 100644 index 00000000000000..dc490d375909fe --- /dev/null +++ b/examples/nextjs-hooks/pages/_document.js @@ -0,0 +1,99 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Document, { Head, Main, NextScript } from 'next/document'; +import flush from 'styled-jsx/server'; + +class MyDocument extends Document { + render() { + const { pageContext } = this.props; + + return ( + + + + {/* Use minimum-scale=1 to enable GPU rasterization */} + + {/* PWA primary color */} + + + + +
+ + + + ); + } +} + +MyDocument.getInitialProps = ctx => { + // Resolution order + // + // On the server: + // 1. app.getInitialProps + // 2. page.getInitialProps + // 3. document.getInitialProps + // 4. app.render + // 5. page.render + // 6. document.render + // + // On the server with error: + // 1. document.getInitialProps + // 2. app.render + // 3. page.render + // 4. document.render + // + // On the client + // 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 ; + }; + + WrappedComponent.propTypes = { + pageContext: PropTypes.object.isRequired, + }; + + return WrappedComponent; + }); + + let css; + // It might be undefined, e.g. after an error. + if (pageContext) { + css = pageContext.sheetsRegistry.toString(); + } + + return { + ...page, + pageContext, + // Styles fragment is rendered after the app and page rendering finish. + styles: ( + +