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:
parent
6ca00bfe31
commit
001230e0a8
11 changed files with 109 additions and 35 deletions
|
@ -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
|
||||
|
||||
|
|
5
examples/with-route-as-modal/app-styles.module.css
Normal file
5
examples/with-route-as-modal/app-styles.module.css
Normal file
|
@ -0,0 +1,5 @@
|
|||
.content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
11
examples/with-route-as-modal/components/Article.js
Normal file
11
examples/with-route-as-modal/components/Article.js
Normal 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
|
28
examples/with-route-as-modal/components/Grid.js
Normal file
28
examples/with-route-as-modal/components/Grid.js
Normal 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>
|
||||
)
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -1,12 +1,6 @@
|
|||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#__next {
|
||||
.postCardGridWrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.postCardGrid {
|
|
@ -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
|
||||
|
|
43
examples/with-route-as-modal/pages/article/[articleId].js
Normal file
43
examples/with-route-as-modal/pages/article/[articleId].js
Normal 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,
|
||||
}
|
||||
}
|
|
@ -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 />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue