Add Route as Modal Page Example (#12945)

### Add dynamic routes to _with-route-as-modal_ example

This PR adds [dynamic routes](https://nextjs.org/docs/routing/dynamic-routes), [getStaticPaths](https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation), and [getStaticProps](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) to the **with-route-as-modal** example. This change might also clear up some confusion here on https://github.com/zeit/next.js/issues/11971

Additionally this PR makes sure each modal route is also a modal **page.**

This is an important distinction and makes sure the experience is the same should the URL (route) be shared as a link. In other words, `index.js` need not be the only "entrypoint" to browsing the website.

With the additions in this PR, each post page is an actual page, so if you were to share the link for **Post 3** you'd get this:

<img src="https://user-images.githubusercontent.com/7191639/82058282-25ad7780-968a-11ea-94f1-9b4a36abccf9.png" width="200px" />

(clickable outer region brings you back to the 'gallery')

**Update:** I have also included the `pathname` to signal the difference in which page component is rendered

Rather than this (previously):

<img src="https://user-images.githubusercontent.com/7191639/82058199-0878a900-968a-11ea-97d2-e9e20c9267fc.png" width="200px" />

I have used a similar approach [here 🔗](https://hashiconf.com/digital-june/schedule/the-hitchhikers-guide-to-terraform-your-infrastructure)
This commit is contained in:
Jimmy Merritello 2020-05-27 16:22:33 -05:00 committed by GitHub
parent 6ca00bfe31
commit 001230e0a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 109 additions and 35 deletions

View file

@ -1,8 +1,8 @@
# with-route-as-modal
On many popular social media, opening a post will update the URL but won't trigger a navigation and will instead display the content inside a modal. This behavior ensure the user won't lose the current UI context (scroll position). The URL still reflect the post's actual page location and any refresh will bring the user there. This behavior ensure great UX without neglecting SEO.
On many popular social media, opening a post will update the URL but won't trigger a navigation and will instead display the content inside a modal. This behavior ensures the user won't lose the current UI context (scroll position). The URL still reflect the post's actual page location and any refresh will bring the user there. This behavior ensures great UX without neglecting SEO.
This example show how to conditionally display a modal based on a route.
This example shows how to conditionally display a modal based on a route.
## Deploy your own

View file

@ -0,0 +1,5 @@
.content {
display: flex;
justify-content: center;
align-items: center;
}

View file

@ -0,0 +1,11 @@
import styles from './styles.module.css'
const Post = ({ id, pathname }) => {
return (
<div className={styles.post}>
I am the article {id}; my pathname is: {pathname}
</div>
)
}
export default Post

View file

@ -0,0 +1,28 @@
import Link from 'next/link'
import styles from './styles.module.css'
export const data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
export default function PostCardGrid() {
return (
<div className={styles.postCardGridWrapper}>
<h2>With QueryString Routing, and a reload won't use the modal</h2>
<div className={styles.postCardGrid}>
{data.map((id, index) => (
<Link key={index} href={`/?postId=${id}`} as={`/post/${id}`}>
<a className={styles.postCard}>{id}</a>
</Link>
))}
</div>
<h2>With Dynamic Routing, and reloads will keep the modal</h2>
<div className={styles.postCardGrid}>
{data.map((id, index) => (
<Link key={index} href="/article/[articleId]" as={`/article/${id}`}>
<a className={styles.postCard}>{id}</a>
</Link>
))}
</div>
</div>
)
}

View file

@ -1,5 +1,11 @@
const Post = ({ id }) => {
return <div className="post">{`I am the post ${id}`}</div>
import styles from './styles.module.css'
const Post = ({ id, pathname }) => {
return (
<div className={styles.post}>
I am the post {id}; my pathname is: {pathname}
</div>
)
}
export default Post

View file

@ -1,11 +0,0 @@
import Link from 'next/link'
const PostCard = ({ id }) => {
return (
<Link href={`/?postId=${id}`} as={`/post/${id}`}>
<a className="postCard">{id}</a>
</Link>
)
}
export default PostCard

View file

@ -1,12 +1,6 @@
body {
margin: 0;
}
#__next {
.postCardGridWrapper {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
flex-direction: column;
}
.postCardGrid {

View file

@ -1,7 +1,11 @@
import '../style.css'
import styles from '../app-styles.module.css'
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
return (
<div className={styles.content}>
<Component {...pageProps} />
</div>
)
}
export default MyApp

View file

@ -0,0 +1,43 @@
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import Modal from 'react-modal'
import Article from '../../components/Article'
import { data } from '../../components/Grid'
Modal.setAppElement('#__next')
const ArticlePage = ({ articleId }) => {
const router = useRouter()
useEffect(() => {
router.prefetch('/')
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<>
<Modal
isOpen={true} // The modal should always be shown on page load, it is the 'page'
onRequestClose={() => router.push('/')}
contentLabel="Post modal"
>
<Article id={articleId} pathname={router.pathname} />
</Modal>
</>
)
}
export default ArticlePage
export function getStaticProps({ params: { articleId } }) {
return { props: { articleId: articleId } }
}
export function getStaticPaths() {
return {
paths: data.map((articleId) => ({
params: { articleId: articleId.toString() },
})),
fallback: false,
}
}

View file

@ -1,12 +1,10 @@
import { useRouter } from 'next/router'
import Modal from 'react-modal'
import Post from '../components/Post'
import PostCard from '../components/PostCard'
import Grid from '../components/Grid'
Modal.setAppElement('#__next')
const posts = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const Index = () => {
const router = useRouter()
@ -17,13 +15,9 @@ const Index = () => {
onRequestClose={() => router.push('/')}
contentLabel="Post modal"
>
<Post id={router.query.postId} />
<Post id={router.query.postId} pathname={router.pathname} />
</Modal>
<div className="postCardGrid">
{posts.map((id, index) => (
<PostCard key={index} id={id} />
))}
</div>
<Grid />
</>
)
}

View file

@ -5,7 +5,7 @@ const PostPage = () => {
const router = useRouter()
const { postId } = router.query
return <Post id={postId} />
return <Post id={postId} pathname={router.pathname} />
}
export default PostPage