From 558c6368a7b6b317a56269f38f9ae2951078a448 Mon Sep 17 00:00:00 2001 From: Gregory Parsons Date: Fri, 8 Dec 2017 14:26:32 -0800 Subject: [PATCH 1/7] adds notes about HOC to handle client routing --- docs/docs/creating-and-modifying-pages.md | 88 +++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/docs/docs/creating-and-modifying-pages.md b/docs/docs/creating-and-modifying-pages.md index 933885cd021f5..fdc6142356824 100644 --- a/docs/docs/creating-and-modifying-pages.md +++ b/docs/docs/creating-and-modifying-pages.md @@ -160,6 +160,94 @@ exports.onCreatePage = async ({ page, boundActionCreators }) => { }; ``` +### Client Route Params + +In order to make a `detail` page at `/widgets/view/ID` and extract the `ID` param, we will need to configure client only routes. + +**Build config:** + +First configure `gatsby-node.js`: + +```javascript +exports.onCreatePage = async ({ page, boundActionCreators }) => { + const { createPage } = boundActionCreators; + + return new Promise((resolve, reject) => { + if (/view/.test(page.path)) { + // Gatsby paths have a trailing `/` + page.matchPath = `${page.path}:id`; + } + + createPage(page); + resolve(); + }); +}; +``` + +**Client:** + +Extracting path params from the route on the client requires that you add a `react-router` `` in your component. + +This can be made simpler by using a HOC: + +```javascript +import React from 'react'; +import PropTypes from 'prop-types'; +import { Route } from 'react-router-dom'; + +// Pass in route config, and the Content component you want rendered +export default (config, Content) => { + const GatsbyClientRoute = () => { + return ( + + ) + }; + + return GatsbyClientRoute; +}; +``` + +Use the HOC on the page component you want to access the path params: + +```javascript +export default GatsbyClientRoute({path: '/widgets/view/:id'}, WidgetPage); +``` + +Full example page: + +```javascript +import React from 'react'; + +import GatsbyClientRoute from '/components/hocs/gatsby-client-route'; + +class WidgetPageContent extends React.Component { + constructor(props) { + super(props); + } + + render() { + const { match } = this.props; + console.log(match.params.id); + return ( +
+ Widget: {match.params.id} +
+ ); + } +}; + +export default GatsbyClientRoute( + // NOTE this must match path.matchPath + {path: '/widgets/view/:id'}, + WidgetPageContent +); +``` + +Using the URL `http://localhost:8000/wigets/view/10` will console log `10` and the markup will say `Widget: 10`. + ### Choosing the page layout By default, all pages will use the layout found at `/layouts/index.js`. From fb5d4bb8ffb1d9a3a40b8fff6caf1085ea87ffe9 Mon Sep 17 00:00:00 2001 From: Gregory Parsons Date: Fri, 8 Dec 2017 17:05:00 -0800 Subject: [PATCH 2/7] fix page.path is required --- docs/docs/creating-and-modifying-pages.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/creating-and-modifying-pages.md b/docs/docs/creating-and-modifying-pages.md index fdc6142356824..f1486eca7aeff 100644 --- a/docs/docs/creating-and-modifying-pages.md +++ b/docs/docs/creating-and-modifying-pages.md @@ -175,7 +175,8 @@ exports.onCreatePage = async ({ page, boundActionCreators }) => { return new Promise((resolve, reject) => { if (/view/.test(page.path)) { // Gatsby paths have a trailing `/` - page.matchPath = `${page.path}:id`; + page.path = `${page.path}:id`; + page.matchPath = page.path; } createPage(page); From 4733d5c1a79b2c642cf2ddd6b233471d6854324c Mon Sep 17 00:00:00 2001 From: Gregory Parsons Date: Sat, 9 Dec 2017 11:39:57 -0800 Subject: [PATCH 3/7] Update creating-and-modifying-pages.md --- docs/docs/creating-and-modifying-pages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/creating-and-modifying-pages.md b/docs/docs/creating-and-modifying-pages.md index f1486eca7aeff..70d2b79cd7612 100644 --- a/docs/docs/creating-and-modifying-pages.md +++ b/docs/docs/creating-and-modifying-pages.md @@ -241,7 +241,7 @@ class WidgetPageContent extends React.Component { }; export default GatsbyClientRoute( - // NOTE this must match path.matchPath +// NOTE this must match path.matchPath {path: '/widgets/view/:id'}, WidgetPageContent ); From a604589bf8cc37e4ed20ffe22252f9534967c1d2 Mon Sep 17 00:00:00 2001 From: Gregory Parsons Date: Sat, 9 Dec 2017 13:10:56 -0800 Subject: [PATCH 4/7] updates notes about server config --- docs/docs/creating-and-modifying-pages.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/docs/creating-and-modifying-pages.md b/docs/docs/creating-and-modifying-pages.md index 70d2b79cd7612..c71218663d184 100644 --- a/docs/docs/creating-and-modifying-pages.md +++ b/docs/docs/creating-and-modifying-pages.md @@ -162,7 +162,7 @@ exports.onCreatePage = async ({ page, boundActionCreators }) => { ### Client Route Params -In order to make a `detail` page at `/widgets/view/ID` and extract the `ID` param, we will need to configure client only routes. +In order to make a "detail" page at `/widgets/view/ID` resolve and extract the `ID` param, we will need to configure client only routes. **Build config:** @@ -175,8 +175,7 @@ exports.onCreatePage = async ({ page, boundActionCreators }) => { return new Promise((resolve, reject) => { if (/view/.test(page.path)) { // Gatsby paths have a trailing `/` - page.path = `${page.path}:id`; - page.matchPath = page.path; + page.matchPath = `${page.path}:id`; } createPage(page); @@ -185,6 +184,20 @@ exports.onCreatePage = async ({ page, boundActionCreators }) => { }; ``` +**Server:** + +When creating links to these view/id pages using react router or any pushstate the pages will resolve until the user hard refreshes the page. This is due to your backend server not knowing how to handle the route. + +Configuration is going to be required to make these pages work on production. Results may vary depending on deployment but a simple use case for NGINX: + +``` +location ~ "([a-z]*)\/view\/(\d*)$" { + try_files $uri /$1/view/index.html; +} +``` + +This directive will provide the `widgets/view/index.html` file for any request like (widgets)/view/1. It will also support other pages by matching the first level of the URL, example http://sitename/sprockets/view/1. + **Client:** Extracting path params from the route on the client requires that you add a `react-router` `` in your component. From 2c848c11591b267c4d707e1535b05f8ed8756708 Mon Sep 17 00:00:00 2001 From: Gregory Parsons Date: Sat, 9 Dec 2017 13:12:14 -0800 Subject: [PATCH 5/7] removes actual url link --- docs/docs/creating-and-modifying-pages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/creating-and-modifying-pages.md b/docs/docs/creating-and-modifying-pages.md index c71218663d184..5cb2844dbc0ad 100644 --- a/docs/docs/creating-and-modifying-pages.md +++ b/docs/docs/creating-and-modifying-pages.md @@ -196,7 +196,7 @@ location ~ "([a-z]*)\/view\/(\d*)$" { } ``` -This directive will provide the `widgets/view/index.html` file for any request like (widgets)/view/1. It will also support other pages by matching the first level of the URL, example http://sitename/sprockets/view/1. +This directive will provide the `widgets/view/index.html` file for any request like (widgets)/view/1. It will also support other pages by matching the first level of the URL, example `http://sitename/sprockets/view/1`. **Client:** From 31d476a2fed77570db23df95d659624feeea543b Mon Sep 17 00:00:00 2001 From: Gregory Parsons Date: Sun, 10 Dec 2017 16:36:13 -0800 Subject: [PATCH 6/7] ensure props get passed --- docs/docs/creating-and-modifying-pages.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/creating-and-modifying-pages.md b/docs/docs/creating-and-modifying-pages.md index 5cb2844dbc0ad..3b2e969a1bda9 100644 --- a/docs/docs/creating-and-modifying-pages.md +++ b/docs/docs/creating-and-modifying-pages.md @@ -211,9 +211,10 @@ import { Route } from 'react-router-dom'; // Pass in route config, and the Content component you want rendered export default (config, Content) => { - const GatsbyClientRoute = () => { + const GatsbyClientRoute = (props) => { return ( From d55e34abb0d081b22302312fd41d40eed45a9c85 Mon Sep 17 00:00:00 2001 From: Kyle Mathews Date: Tue, 12 Dec 2017 18:06:27 -0800 Subject: [PATCH 7/7] Copy tweaks --- docs/docs/creating-and-modifying-pages.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/docs/creating-and-modifying-pages.md b/docs/docs/creating-and-modifying-pages.md index 3b2e969a1bda9..df9a46d9042d1 100644 --- a/docs/docs/creating-and-modifying-pages.md +++ b/docs/docs/creating-and-modifying-pages.md @@ -162,7 +162,9 @@ exports.onCreatePage = async ({ page, boundActionCreators }) => { ### Client Route Params -In order to make a "detail" page at `/widgets/view/ID` resolve and extract the `ID` param, we will need to configure client only routes. +Gatsby can create client-only routes which take paramaters. + +We'll walk quickly through how to setup a route on your site like `/widgets/view/ID`. **Build config:** @@ -173,6 +175,7 @@ exports.onCreatePage = async ({ page, boundActionCreators }) => { const { createPage } = boundActionCreators; return new Promise((resolve, reject) => { + // Add client route for all paths matching `/view/*` if (/view/.test(page.path)) { // Gatsby paths have a trailing `/` page.matchPath = `${page.path}:id`; @@ -186,9 +189,9 @@ exports.onCreatePage = async ({ page, boundActionCreators }) => { **Server:** -When creating links to these view/id pages using react router or any pushstate the pages will resolve until the user hard refreshes the page. This is due to your backend server not knowing how to handle the route. +Links to these pages will work well client-side but fail if a user tries to visit a page directly (i.e. load the page from the server). This is due to your backend server not knowing how to handle the route. -Configuration is going to be required to make these pages work on production. Results may vary depending on deployment but a simple use case for NGINX: +Some server configuration is required to make these types of pages work in production. This configuration will vary depending on your server environment but here's a simple example configuration for NGINX: ``` location ~ "([a-z]*)\/view\/(\d*)$" { @@ -200,7 +203,7 @@ This directive will provide the `widgets/view/index.html` file for any request l **Client:** -Extracting path params from the route on the client requires that you add a `react-router` `` in your component. +Extracting path params from the route on the client requires that you use the `react-router` `` in your component. This can be made simpler by using a HOC: