Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update layouts example to persist state across client-side transitions. #26706

Merged
merged 3 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/layout-component/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Layout component example

This example shows a very common use case when building websites where you need to repeat some sort of layout for all your pages. Our pages are: `home`, `about` and `contact` and they all share the same `<head>` settings, the `<nav>` and the `<footer>`. Further more, the title (and potentially other head elements) can be sent as a prop to the layout component so that it's customizable in all pages.
This example shows a very common use case when building websites where you need to repeat some sort of layout for all your pages. Our pages are: `home`, `about` and `contact` and they all share the same layout and sidebar.

## Preview

Expand Down
35 changes: 6 additions & 29 deletions examples/layout-component/components/layout.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,13 @@
import Link from 'next/link'
import Head from 'next/head'
import styles from './layout.module.css'

export default function Layout({
children,
title = 'This is the default title',
}) {
export default function Layout({ children }) {
return (
<div>
<>
<Head>
<title>{title}</title>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
<title>Layouts Example</title>
</Head>
<header>
<nav>
<Link href="/">
<a>Home</a>
</Link>{' '}
|
<Link href="/about">
<a>About</a>
</Link>{' '}
|
<Link href="/contact">
<a>Contact</a>
</Link>
</nav>
</header>

{children}

<footer>{'I`m here to stay'}</footer>
</div>
<main className={styles.main}>{children}</main>
</>
)
}
9 changes: 9 additions & 0 deletions examples/layout-component/components/layout.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.main {
display: flex;
height: calc(100vh - 64px);
background-color: white;
}

.main > section {
padding: 32px;
}
19 changes: 19 additions & 0 deletions examples/layout-component/components/sidebar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Link from 'next/link'
import styles from './sidebar.module.css'

export default function Sidebar() {
return (
<nav className={styles.nav}>
<input className={styles.input} placeholder="Search..." />
<Link href="/">
<a>Home</a>
</Link>
<Link href="/about">
<a>About</a>
</Link>
<Link href="/contact">
<a>Contact</a>
</Link>
</nav>
)
}
39 changes: 39 additions & 0 deletions examples/layout-component/components/sidebar.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.nav {
height: 100%;
display: flex;
flex-direction: column;
width: 250px;
background-color: #fafafa;
padding: 32px;
border-right: 1px solid #eaeaea;
}

.nav > a {
margin: 8px 0;
text-decoration: none;
background: white;
border-radius: 4px;
font-size: 14px;
padding: 12px 16px;
text-transform: uppercase;
font-weight: 600;
letter-spacing: 0.025em;
color: #333;
border: 1px solid #eaeaea;
transition: all 0.125s ease;
}

.nav > a:hover {
background-color: #eaeaea;
}

.input {
margin: 32px 0;
text-decoration: none;
background: white;
border-radius: 4px;
border: 1px solid #eaeaea;
font-size: 14px;
padding: 8px 16px;
height: 28px;
}
12 changes: 12 additions & 0 deletions examples/layout-component/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#__next {
display: flex;
flex-direction: column;
min-height: 100vh;
}

body {
margin: 0;
font-size: 24px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
}
8 changes: 8 additions & 0 deletions examples/layout-component/pages/_app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import '../global.css'

export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout || ((page) => page)

return getLayout(<Component {...pageProps} />)
}
37 changes: 34 additions & 3 deletions examples/layout-component/pages/about.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
import Layout from '../components/layout'
import Sidebar from '../components/sidebar'

export default function About() {
return (
<Layout title="About us">
<div>About us</div>
</Layout>
<section>
<h2>Layout Example (About)</h2>
<p>
This example adds a property <code>getLayout</code> to your page,
allowing you to return a React component for the layout. This allows you
to define the layout on a per-page basis. Since we're returning a
function, we can have complex nested layouts if desired.
</p>
<p>
When navigating between pages, we want to persist page state (input
values, scroll position, etc) for a Single-Page Application (SPA)
experience.
</p>
<p>
This layout pattern will allow for state persistence because the React
component tree is persisted between page transitions. To preserve state,
we need to prevent the React component tree from being discarded between
page transitions.
</p>
<h3>Try It Out</h3>
<p>
To visualize this, try tying in the search input in the{' '}
<code>Sidebar</code> and then changing routes. You'll notice the input
state is persisted.
</p>
</section>
)
}

About.getLayout = (page) => (
<Layout>
<Sidebar />
{page}
</Layout>
)
37 changes: 34 additions & 3 deletions examples/layout-component/pages/contact.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
import Layout from '../components/layout'
import Sidebar from '../components/sidebar'

export default function Contact() {
return (
<Layout title="Contact us">
<div>Contact</div>
</Layout>
<section>
<h2>Layout Example (Contact)</h2>
<p>
This example adds a property <code>getLayout</code> to your page,
allowing you to return a React component for the layout. This allows you
to define the layout on a per-page basis. Since we're returning a
function, we can have complex nested layouts if desired.
</p>
<p>
When navigating between pages, we want to persist page state (input
values, scroll position, etc) for a Single-Page Application (SPA)
experience.
</p>
<p>
This layout pattern will allow for state persistence because the React
component tree is persisted between page transitions. To preserve state,
we need to prevent the React component tree from being discarded between
page transitions.
</p>
<h3>Try It Out</h3>
<p>
To visualize this, try tying in the search input in the{' '}
<code>Sidebar</code> and then changing routes. You'll notice the input
state is persisted.
</p>
</section>
)
}

Contact.getLayout = (page) => (
<Layout>
<Sidebar />
{page}
</Layout>
)
39 changes: 35 additions & 4 deletions examples/layout-component/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
import Layout from '../components/layout'
import Sidebar from '../components/sidebar'

export default function Home() {
export default function Index() {
return (
<Layout>
<div>Hello World.</div>
</Layout>
<section>
<h2>Layout Example (Index)</h2>
<p>
This example adds a property <code>getLayout</code> to your page,
allowing you to return a React component for the layout. This allows you
to define the layout on a per-page basis. Since we're returning a
function, we can have complex nested layouts if desired.
</p>
<p>
When navigating between pages, we want to persist page state (input
values, scroll position, etc) for a Single-Page Application (SPA)
experience.
</p>
<p>
This layout pattern will allow for state persistence because the React
component tree is persisted between page transitions. To preserve state,
we need to prevent the React component tree from being discarded between
page transitions.
</p>
<h3>Try It Out</h3>
<p>
To visualize this, try tying in the search input in the{' '}
<code>Sidebar</code> and then changing routes. You'll notice the input
state is persisted.
</p>
</section>
)
}

Index.getLayout = (page) => (
<Layout>
<Sidebar />
{page}
</Layout>
)