Your First Next.js & Drupal Customization
Before You Begin
This guide assumes the reader has working knowledge of React, and little to no knowledge of Next.js.
Data Fetching in Next.js
Next.js offers various ways to fetch data and render content. Please see the Next.js Data Fetching Overview for an in depth look at each. For the purposes of this guide, we will cover creating a page with Server Side Rendering (SSR) and Static Site Generation (SSG).
Fetching Drupal Content with DrupalState
The next-drupal-starter
has a dependency on @pantheon-systems/drupal-kit
,
which implements
Drupal State -
a tool that helps fetch and store data from Drupal into the local app state.
SSR Example
To render a page with Server Side Rendering (SSR) in Next.js, export an async
function called
getServerSideProps
from that page. Inside of this function, we can use Drupal State to fetch data
from Drupal and pass it to the component as props.
import { DrupalState } from '@pantheon-systems/drupal-kit';
export default function Articles({ articles }) {
return <pre>{JSON.stringify(articles, null, 4)}</pre>;
}
export async function getServerSideProps(context) {
const { locale } = context; // use the current locale in order to fetch correct translation
const store = new DrupalState({
apiBase: process.env.BACKEND_URL,
defaultLocale: locale,
});
const articles = await store.getObject({
objectName: 'node--article',
// Drupal State allows us to use a graphql query to get the data we need and nothing extra
query: `
{
title
body
created
path {
alias
}
}
`,
});
return {
props: {
articles,
},
};
}
SSG Example
If we want to use SSG, export
getStaticProps
from a page to generate that page at build time instead of request time.
Let's build a page using getStaticProps
that lists recipes from our Drupal
instance.
import { DrupalState } from '@pantheon-systems/drupal-kit';
export default function Recipes({ recipes }) {
return <pre>{JSON.stringify(recipes, null, 4)}</pre>;
}
export async function getStaticProps(context) {
const { locale } = context; // use the current locale in order to fetch correct translation
const store = new DrupalState({
apiBase: process.env.BACKEND_URL,
defaultLocale: locale,
});
const recipes = await store.getObject({
objectName: 'node--recipe',
query: `
{
title
field_ingredients
field_number_of_servings
field_preparation_time
field_recipe_instruction
field_summary
created
path {
alias
}
}
`,
});
return {
props: {
recipes,
},
};
}
Notice the only real difference for this page–besides the fact we are fetching
recipes instead of articles–is the use of getStaticProps
instead of
getServerSideProps
.
Client Side Rendering (CSR) Example
In some cases, you may wish to fetch and render the data on the client. In these
cases, you can leverage the same DrupalState
store that is available to you in
the server contexts, HOWEVER, it should be noted this is not the same instance
of the store that exists on the server, thus the store is not shared between the
client and the server. Client side rendering is not usually necessary with a
framework like Next.js.
The CSR pattern here is the same as it is with vanilla React.
site through CORS to achieve CSR. Also, be aware that the store is not shared between the client and server contexts.
import { DrupalState } from '@pantheon-systems/drupal-kit';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
export default function Articles() {
const { locale } = useRouter();
const [articles, setArticles] = useState([]);
/**
* We recommend creating as few instances of
* DrupalState as possible and reusing them
* throughout the application.
* We are creating a new one here
* for example purposes.
*/
const store = new DrupalState({
/**
* In order to create the store on the client
* side, you will need to expose your
* BACKEND_URL in your next.config.env
* so that it can be read on the client side.
* This should not cause any issues security
* wise if your Drupal instance is
* configured appropriately.
*/
apiBase: process.env.backendUrl,
defaultLocale: locale,
});
useEffect(async () => {
if (!articles.length) {
const data = await store.getObject({
objectName: 'node--article',
});
setArticles(data);
}
}, []);
if (articles) {
return <pre>{JSON.stringify(articles, null, 4)}</pre>;
}
}
Next Steps
From here, it's time to see the code in action. Start the app if it's not
already running and head to http://localhost:3000/articles
. You should see the
SSR'd Articles
page. Navigate to /recipes
to see the SSG'd Recipes
page,
and /csr-articles
to se the CSR'd page.
From this point, you may want to adjust the markup and style of the Articles
and Recipes
components, or move on to another custom page. For more
information on composing react components, see
Composing Components
Conclusion
In this guide we created a new page using SSR, SSG, and CSR utilizing Drupal State to fetch data from our Drupal instance.