Reputation: 3028
I'm trying to follow the basic examples on the Gatsby website. These are my codes so far:
// pages/app.js
import { Router } from '@reach/router';
import { Link } from 'gatsby';
import * as React from 'react';
import Browse from '../components/Browse';
import Upload from '../components/Upload';
const AppPage = () => (
<>
<nav>
<Link to "/app/browse">Browse Link</Link>
<Link to "/app/upload">Upload Link</Link>
</nav>
<main>
<Router basepath="/app">
<Browse path="/browse">Browse</Browse>
<Upload path="/upload">Upload</Upload>
</Router>
</main>
</>
);
export default AppPage;
// components/Browse.tsx
import * as React from 'react';
import { RouteComponentProps } from '@reach/router';
type BrowseProps = {
children?: string,
} & RouteComponentProps;
const Browse = ({ children }: BrowseProps) => <div>{children}</div>;
Browse.defaultProps = {
children: '',
};
export default Browse;
// components/Upload.tsx
// Identical to Browse.tsx, except it's named Upload
type UploadProps {...}
const Upload = ...;
export default Upload;
To help configure client-only paths, I'm using gatsby-plugin-create-client-paths
to help automate the process as suggested on the site. It has been added to gatsby-config.js
like so:
// gatsby-config.js
plugins: [
"gatsby-plugin-react-helmet",
{
resolve: "gatsby-plugin-create-client-paths",
options: {
prefixes: ["/app/*"],
},
},
{
resolve: "gatsby-plugin-manifest",
options: {
icon: "src/images/icon.png",
},
},
]
As far as I can tell, that should be all I need to get it working. So I started the development server:
npm run develop
I successfully opened http://localhost:8000/app/
and the two Links
are successfully rendered, but when I click on either of them, a runtime error occurred:
One unhandled runtime error found in your files. See the list below to fix it:
Error in function eval in ./node_modules/@gatsbyjs/reach-router/es/index.js:698
Cannot read property 'path' of undefined
./node_modules/@gatsbyjs/reach-router/es/index.js:698
696 | return React.Children.map(element.props.children, createRoute(basepath));
697 | }
> 698 | !(element.props.path || element.props.default || element.type === Redirect) ? process.env.NODE_ENV !== "production" ? invariant(false, "<Router>: Children of <Router> must have a `path` or `default` prop, or be a `<Redirect>`. None found on element type `" + element.type + "`") : invariant(false) : void 0;
699 |
700 | !!(element.type === Redirect && (!element.props.from || !element.props.to)) ? process.env.NODE_ENV !== "production" ? invariant(false, "<Redirect from=\"" + element.props.from + "\" to=\"" + element.props.to + "\"/> requires both \"from\" and \"to\" props when inside a <Router>.") : invariant(false) : void 0;
701 |
What does this mean? Am I missing something? Is it because I'm using the development and not production environment, causing it to fail?
Update: Following the answer by Ferran, I modified my code as follows, refactoring pages/index.js
to pages/app/[...].js
// pages/app/[...].js
import { Router } from '@reach/router';
import { Link } from 'gatsby';
import * as React from 'react';
import Browse from '../../components/Browse';
import Upload from '../../components/Upload';
const AppPage = () => (
<>
<nav>
<Link to "/app/browse">Browse Link</Link>
<Link to "/app/upload">Upload Link</Link>
</nav>
<main>
<Router basepath="/app">
<Browse path="/browse">Browse</Browse>
<Upload path="/upload">Upload</Upload>
</Router>
</main>
</>
);
export default AppPage;
All other files remain unchanged. However, the error persists at http://localhost:8000/app/
after clicking a link.
Update: Tried adding a Home
route:
// pages/app/[...].js
import { Router } from '@reach/router';
import { Link } from 'gatsby';
import * as React from 'react';
import Browse from '../../components/Browse';
import Home from '../../components/Home';
import Upload from '../../components/Upload';
const AppPage = () => (
<>
<nav>
<Link to "/app/">Home Link</Link>
<Link to "/app/browse">Browse Link</Link>
<Link to "/app/upload">Upload Link</Link>
</nav>
<main>
<Router basepath="/app">
<Browse path="/browse">Browse</Browse>
<Upload path="/upload">Upload</Upload>
<Browse path="/">Home</Browse>
</Router>
</main>
</>
);
export default AppPage;
Upon adding this in, the same error immediately triggered at http://localhost:8000/app/
. After removing the Home
route but not the Link
, the page can load again. Clicking Home Link at this point doesn't trigger any error.
Upvotes: 1
Views: 1927
Reputation: 29320
What seems to be happening is that your paths are not found by Gatsby. I think you only need to move your app.js
in src/pages/app/[...].js
(renaming the file to [...].js
).
You can follow an official Gatsby example in their GitHub. The code from Gatsby's docs suggests:
// src/pages/app/[...].js
import React from "react"
import { Router } from "@reach/router"
import Layout from "../components/Layout"
import Profile from "../components/Profile"
import Details from "../components/Details"
import Login from "../components/Login"
import Default from "../components/Default"
import PrivateRoute from "../components/PrivateRoute"
const App = () => {
return (
<Layout>
<Router basepath="/app">
<PrivateRoute path="/profile" component={Profile} />
<PrivateRoute path="/details" component={Details} />
<Login path="/login" />
<Default path="/" />
</Router>
</Layout>
)
}
export default App
The [...].js
notation is using the File System Route API, which is marking any dynamic segment of the URL after /app
(because of the folder structure, app/[...].js
).
Upvotes: 1