Skip to content

Commit

Permalink
add with-next-layouts example
Browse files Browse the repository at this point in the history
  • Loading branch information
tz5514 committed Jan 12, 2018
1 parent 69950e8 commit 8649e43
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 0 deletions.
19 changes: 19 additions & 0 deletions examples/with-next-layouts/layouts/AppLayout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'
import delay from '../modules/delay'

export default class AppLayout extends React.Component {
static async getInitialProps () {
return {
delay: await delay(1000)
}
}

render () {
return (
<div>
<h1>App header</h1>
{this.props.children}
</div>
)
}
}
22 changes: 22 additions & 0 deletions examples/with-next-layouts/layouts/ContentLayout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react'
import delay from '../modules/delay'
import AppLayout from './AppLayout'

export default class ContentLayout extends React.Component {
static parentLayout = AppLayout
static async getInitialProps () {
return {
delay: await delay(2000)
}
}

render () {
return (
<div>
<hr />
{this.props.children}
<hr />
</div>
)
}
}
6 changes: 6 additions & 0 deletions examples/with-next-layouts/modules/delay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default function delay (ms) {
return new Promise(resolve => setTimeout(() => {
console.log(`sleep ${ms} ms.`)
resolve(ms)
}, ms))
}
81 changes: 81 additions & 0 deletions examples/with-next-layouts/modules/next-layouts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from 'react'
const defaultOptions = {
getInitialPropsMode: 'sequential'
}

export default function applyLayout (PageComponent, options) {
options = Object.assign({}, defaultOptions, options)

if (!isFunction(PageComponent.layout)) {
warn('Missing static property "layout" of page component.')
return PageComponent
}

if (isFunction(PageComponent.renderPage)) {
warn('You should not define static property "renderPage" of page component when the layout is applying')
return PageComponent
}

// collect layouts & getInitialProps
let layouts = [PageComponent.layout]
while (isFunction(layouts[0].parentLayout)) {
layouts.unshift(layouts[0].parentLayout)
}
const layoutGetInitialPropsList = layouts.map(Layout => isFunction(Layout.getInitialProps) ? Layout.getInitialProps : () => ({}))
const pageGetInitialProps = isFunction(PageComponent.getInitialProps) ? PageComponent.getInitialProps : () => ({})

PageComponent.getInitialProps = async(ctx) => {
let layoutPropsList = []
let pageProps

if (options.getInitialPropsMode === 'sequential') {
for (const layoutGetInitialProps of layoutGetInitialPropsList) {
const layoutProps = await layoutGetInitialProps(ctx)
layoutPropsList.push(layoutProps)
}
pageProps = await pageGetInitialProps(ctx)
} else if (options.getInitialPropsMode === 'concurrent') {
const promises = layoutGetInitialPropsList.map(layoutGetInitialProps => layoutGetInitialProps(ctx))
promises.push(pageGetInitialProps(ctx))
const promiseResults = await Promise.all(promises)
pageProps = promiseResults.pop()
layoutPropsList = promiseResults
}

return { layoutPropsList, pageProps }
}

PageComponent.renderPage = ({ Component, props: { layoutPropsList, pageProps }, url }) => {
return renderLayout({ Component, layouts, pageProps, layoutPropsList, url })
}

return PageComponent
}

function renderLayout ({ Component, layouts, pageProps, layoutPropsList, url }) {
const Layout = layouts[0]
const layoutProps = layoutPropsList[0]
return (Layout) ? (
<Layout {...layoutProps} pageProps={pageProps} url={url}>
{renderLayout({
Component,
layouts: layouts.slice(1, layouts.length),
pageProps,
layoutPropsList: layoutPropsList.slice(1, layoutPropsList.length),
url
})}
</Layout>
) : (
<Component {...pageProps} url={url} />
)
}

function isFunction (func) {
return typeof func === 'function'
}

function warn (message) {
if (process.env.NODE_ENV !== 'production') {
console.error(message)
}
}
15 changes: 15 additions & 0 deletions examples/with-next-layouts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "with-next-layouts",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
},
"license": "ISC"
}
23 changes: 23 additions & 0 deletions examples/with-next-layouts/pages/about.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react'
import delay from '../modules/delay'
import applyLayout from '../modules/next-layouts'
import ContentLayout from '../components/ContentLayout'

class AboutPage extends React.Component {
static layout = ContentLayout
static async getInitialProps () {
return {
delay: await delay(3000)
}
}

render () {
return (
<p>about</p>
)
}
}

export default applyLayout(AboutPage, {
getInitialPropsMode: 'concurrent'
})
27 changes: 27 additions & 0 deletions examples/with-next-layouts/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import Link from 'next/link'
import delay from '../modules/delay'
import applyLayout from '../modules/next-layouts'
import ContentLayout from '../components/ContentLayout'

class IndexPage extends React.Component {
static layout = ContentLayout
static async getInitialProps () {
return {
delay: await delay(3000)
}
}

render () {
return (
<div>
index
<Link href='/about'>
<a>about</a>
</Link>
</div>
)
}
}

export default applyLayout(IndexPage)

0 comments on commit 8649e43

Please sign in to comment.