We basically wrote the tutorial the way that we wanted the code to work and then we made the tutorial work by writing the code. As opposed to Readme Driven Development which I've written about this is tutorial driven development.
Tom Preston-Werner - Full Stack Radio
Introduction | Tutorial |
---|---|
I - Redwood Philosophies | Part 1 - Setup |
II - Fullstack React | Part 2 - Routes |
III - Jamstack | Part 3 - Prisma |
IV - Serverless | Part 4 - Cells |
Part 5 - Contact | |
Part 6 - GraphQL | |
Part 7 - Deploy | |
Part 8 - Auth |
In part 1 we installed and created our first RedwoodJS application. We used:
-
yarn create redwood-app
to generate the initial app -
redwood generate page
to create:- A
HomePage
folder containing aHomePage
file containing aHomePage
component - An
AboutPage
folder containing anAboutPage
file containing anAboutPage
component.
- A
If at any point you're having trouble remembering commands enter:
yarn rw --help
You'll get a quick reminder of all the commands.
We were able to navigate between the different pages in our browser by entering /about
for the About page or a slash (/
) for the Home page. Depending on your experience with React this may have been surprising to you.
If you've worked on routing in React before you know that to achieve this there needs to be an entirely different package imported containing the router and then your routes need to be wrapped in a <BrowserRouter>
or <Router>
component to give the router access to your pages. Well guess what.....
2.1 Routes.js
// web/src/Routes.js
import { Router, Route } from '@redwoodjs/router'
const Routes = () => {
return (
<Router>
<Route path="/about" page={AboutPage} name="about" />
<Route path="/" page={HomePage} name="home" />
<Route notfound page={NotFoundPage} />
</Router>
)
}
export default Routes
In our web/src
folder we have a file called Routes.js
. When we used the CLI to generate HomePage
and AboutPage
we also created these routes.
- All Page components from
web/src/pages
are auto-imported - Nested directories are supported, and should be uppercase
- Each subdirectory will be prepended onto the component name
Examples:
web/src/pages/HomePage/HomePage.js
-> HomePage
web/src/pages/Admin/BooksPage/BooksPage.js
-> AdminBooksPage
2.2 index.js
The other file in our web/src
folder is index.js
which is our root component that ReactDOM renders to the screen.
// web/src/index.js
import ReactDOM from 'react-dom'
import { RedwoodProvider, FatalErrorBoundary } from '@redwoodjs/web'
import FatalErrorPage from 'src/pages/FatalErrorPage'
import Routes from 'src/Routes'
import './index.css'
ReactDOM.render(
<FatalErrorBoundary page={FatalErrorPage}>
<RedwoodProvider>
<Routes />
</RedwoodProvider>
</FatalErrorBoundary>,
document.getElementById('redwood-app')
)
In React all components are composable which encourages the creation of reusable UI components that present data that changes over time. Traditionally, web application UIs were built using templates or HTML directives.
But in React you always have a root component that contains other components and those components may contain other components. If that's a little confusing just give it some time and it'll start to click as this series goes on.
The important take away is:
- Your routes and thus all the website's pages are contained within the
<RedwoodProvider>
tags - The provider itself is contained within
<FatalErrorBoundary>
which is taking in<FatalErrorPage>
as a prop. This defaults your website to an error page if all else fails.
2.3 Link
When it comes to routing, matching URLs to Pages is only half the equation. The other half is generating links to your pages. We'll add a link to our page so we can navigate between our Home page and About page by clicking on the link. We'll need to add 3 things to our HomePage
file:
- Import
Link
androutes
from@redwoodjs/router
<Link to={}>About</Link>
- Pass
routes.about()
into<Link to={}>
// web/src/pages/HomePage/HomePage.js
import { Link, routes } from '@redwoodjs/router'
const HomePage = () => {
return (
<>
<header>
<h1>ajcwebdev</h1>
<nav>
<ul>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
</header>
<main>
<p><a href="https://dev.to/ajcwebdev">Blog</a></p>
<p><a href="https://twitter.com/ajcwebdev">Twitter</a></p>
<p><a href="https://github.com/ajcwebdev">GitHub</a></p>
</main>
</>
)
}
export default HomePage
You use a Link
to generate a link to one of your routes. The routes
object can access URL generators for any of your routes. We call the functions on the routes
object named route functions because they are named after whatever you specify in the name
prop of the Route
.
Return to your browser to see the changes to your Home page.
Click the link and you will be brought to your About page.
We also want to be able to navigate back to our Home page once we are on our About page. We'll do the same three steps but with a different prop:
- Import
Link
androutes
from@redwoodjs/router
<Link to={}>Return home</Link>
- Pass
routes.home()
into<Link to={}>
// web/src/pages/AboutPage/AboutPage.js
import { Link, routes } from '@redwoodjs/router'
const AboutPage = () => {
return (
<>
<header>
<h1>ajcwebdev</h1>
<nav>
<ul>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
</header>
<main>
<p>Full stack web developer</p>
<Link to={routes.home()}>Return home</Link>
</main>
</>
)
}
export default AboutPage
Everything is exactly the same except we pass in routes.home()
instead of routes.about()
because we want to navigate to our Home page this time. Return to your About page.
There is now a link that will take you back to the Home page when clicked.
2.4 redwood generate layout
You've probably been on a website before. Usually there's some kind of navigation bar at the top and footer at the bottom that stays consistent as you travel around the website. Redwood's folder structure is designed to make this really easy.
Remember what I said before about everything being a component containing other components? Pages contain components and your layout will contain all of your pages. This is natural to do in React because pages and layouts are themselves components.
We can generate a file for our layout with yarn redwood generate layout
or yarn rw g layout
. This will work a lot like the generate page
commands from earlier.
yarn rw g layout blog
This will create a folder inside web/src/layouts
instead of web/src/pages
because we are generating a layout and not a page.
In your layouts folder you'll see the following files:
BlogLayout.js
BlogLayout.test.js
BlogLayout.stories.js
2.5 BlogLayout
// web/src/layouts/BlogLayout/BlogLayout.js
const BlogLayout = ({ children }) => {
return <>{children}</>
}
export default BlogLayout
children
is where the magic will happen. Any page content given to the layout will be rendered here.
// web/src/layouts/BlogLayout/BlogLayout.js
import { Link, routes } from '@redwoodjs/router'
const BlogLayout = ({ children }) => {
return (
<>
<header>
<h1>
<Link to={routes.home()}>ajcwebdev</Link>
</h1>
<nav>
<ul>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
</header>
<main>{children}</main>
</>
)
}
export default BlogLayout
Now we'll add a wrapper around the content returned in our HomePage and AboutPage components.
// web/src/pages/HomePage/HomePage.js
import BlogLayout from 'src/layouts/BlogLayout'
const HomePage = () => {
return (
<BlogLayout>
<p><a href="https://dev.to/ajcwebdev">Blog</a></p>
<p><a href="https://twitter.com/ajcwebdev">Twitter</a></p>
<p><a href="https://github.com/ajcwebdev">GitHub</a></p>
</BlogLayout>
)
}
export default HomePage
We can remove the import for Link and routes from HomePage since those are now in the Layout.
// web/src/pages/AboutPage/AboutPage.js
import BlogLayout from 'src/layouts/BlogLayout'
const AboutPage = () => {
return (
<BlogLayout>
<p>Full stack web developer</p>
</BlogLayout>
)
}
export default AboutPage
The import statement uses src/layouts/BlogLayout
and not ../src/layouts/BlogLayout
or ./src/layouts/BlogLayout
.
- This is a convenience feature so you don't need to worry about the nesting of your folders.
-
src
is an alias to thesrc
path in the current workspace. If you're working in web thensrc
points toweb/src
and inapi
it points toapi/src
.
If we look at our Home pages now it should look and behave the same way as before except we have turned our title in the <h1>
tag into a Home page link.
Our about page is the same except we have removed the link to return Home since we can now click the title.
In the next part we'll start working with a database and learn to create, retrieve, update, and destroy blog posts.
Discussion