next-slicezone Technical Reference

This guide will explain what the next-slicezone package does, how to install it and how to use it.


Introduction

The next-slicezone package exports two lifecycle hooks (useGetStaticProps, useGetStaticPaths) that allow you to fetch associated data of documents on Prismic and get the static paths of a given route. It also exports a component (SliceZone) that matches your Next.js components with Prismic Slices.

Together they render front-end components for each of your Prismic documents. You'll see how to use these later, but first, you should learn how to install and configure the package.

Package Version

This article refers to the latest version of the next-slicezone package. The latest version of this package no longer requires next-transpile-modules: See npm to check the latest version.

Dependencies installation

Install the next-slicezone package via a package manager:

  • npm
  • Yarn
Copy
npm i next-slicezone
Copy
yarn add next-slicezone

You should also install @prismicio/client which will be used to query the Prismic API:

  • npm
  • Yarn
Copy
npm install @prismicio/client
Copy
yarn install @prismicio/client

Project files configuration

You will need to configure a few project files to use this package.

The sm.json file

Create a file at the root of your project called sm.json. This file is a configuration file for the slice-machine-ui and your <SliceZone> component which will use this file to find the location of your Slice libraries.

Accepted Attributes

Usage

apiEndpoint

You can specify your Prismic API endpoint here and import it throughout your project.

libraries

Used to specify a Slices directory (@/my-slices), nested Slice directories (@/slices/new-library) or library packages (like react essential-slices).

_latest

Used to specify the version of slice-machine-ui.

storybook

Used to specify the port in which to open a storybook integration.

Example file

Copy
{
  "apiEndpoint": "https://your-repo-name.cdn.prismic.io/api/v2",
  "libraries": [
    "@/slices",
    "@/my-slices/new-library",
    "essential-slices"
  ],
  "_latest": "0.1.0",
  "storybook": "http://localhost:8888"
}

createResolver and SliceResolver functions

The createResolver function will generate an sm-resolver.js file in the root of your project every time you change your Slices structure (rename, add, delete a slice, add a library, etc.). This file contains the SliceResolver function which is used to automatically match Slices and their content coming from Prismic to the local components in your project. You will need to import it when building a page and pass it to the <SliceZone> component.

To do this, create a 〜/pages/_document.js file and add the createResolver method to its getInitialProps method:

Copy
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { createResolver } from 'next-slicezone/resolver' // import the function here

export default class extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    /* In development, generate an sm-resolver.js file
    that will map slices to components */
    if (process.env.NODE_ENV === 'development') {
      await createResolver()
    }
    return { ...initialProps }
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

Example sm-resolver.js file

This file contains the Javascript SliceResolver function which you need to import when building a page and pass it to the <SliceZone> component. You can see how to do this further down the article where we discuss the <SliceZone>.

Copy
import { Fragment } from 'react'
import * as Slices from './slices'

const __allSlices = {  ...Slices, }

const NotFound = ({ sliceName, slice, i }) => {
  console.error(`[sm-resolver] component "${sliceName}" not found at index ${i}.`)
  console.warn(`slice data: ${slice}`)
  return process.env.NODE_ENV !== 'production' ? (
    <div
      style={{
        height: '30vh',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        flexDirection: 'column',
        textAlign: 'center',
        background: '#FAFAFA'
      }}
    >
      <h2>
        Slice "{sliceName}" not found.
      </h2>
      <p style={{ maxWidth: '320px', fontSize: '16px' }}>
        Check that you registered this component in your slices library!
      </p>
    </div>
  ) : <Fragment />
}

export default function SliceResolver({ sliceName, ...rest }) {
  return __allSlices[sliceName] ? __allSlices[sliceName] : () => <NotFound sliceName={sliceName} {...rest} />
}

Data Fetching

Next.js offers two data fetching functions:

getStaticProps()

which gets the data for statically-generated pages

getStaticPaths()

which determines all of the routes for statically-generated dynamic pages

next-slicezone extends the functionality of those hooks with useGetStaticPaths() and useGetStaticProps(),

useGetStaticProps

useGetStaticProps can be used on every page using the SliceZone. It's responsible for:

  • fetching content from Prismic
  • returning a pre-written Next getStaticProps

apiParams

useGetStaticProps takes an apiParams object or function as an argument.

The object argument allows you to specify static props to send to your query such as a language code.

The function argument gives you access to the params, previewData, and preview objects to help build your queries and send dynamic data such as document UIDs from the URL bar to the query. The returned data can also be used when building static paths which you can see in the useGetStaticPaths example below.

client

function (required)

Receives a Prismic client. Example:

Prismic.client(apiEndpoint)

apiParams

object

Object or function passed to client apiOptions. The function gives you access to the params, previewData, and preview objects. Static Object Example:

apiParams: {
lang: 'fr-fr',
},

queryType

string

Defines whether the Custom Type is a singleton or repeatable. Defaults to 'repeat'. Example:

'single'

type

string

Custom Type to query. Defaults to 'page'. Example:

'blog_post'

slicesKey

string

Key of slices array in API response (doc.data.[slicesKey]) Defaults to slices. Example:

'MySliceZone'

extra params used by getStaticProps, like notFound or redirect. Example:

{ revalidate: true }

Hook example only

In this dynamic example below, we query a repeatable page type by uid from the URL.

See a full-page example further down the article.

  • [uid].js (dynamic file name)
  • Deprecated method (Before V0.1.0)
Copy
import Prismic from '@prismicio/client'
import { useGetStaticProps } from 'next-slicezone/hooks'

export const getStaticProps = useGetStaticProps({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  queryType: 'repeat',
  type: 'page',
  slicesKey: 'MySliceZone',
  getStaticPropsParams: {
    notFound: false
  },
  apiParams({ params }) {
    // params are passed by getStaticPaths
    return {
      lang: params.lang,
      uid: params.uid
    }
  }
})
Copy
export const getStaticProps = useGetStaticProps({  
   client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
   uid: ({ params }) => params.uid
})

useGetStaticPaths

useGetStaticPaths can be used in dynamic pages to define the static paths to be generated. It returns a function to be passed directly to Next.js's getStaticPaths function. It will fetch content from Prismic using dynamic properties.

useGetStaticPaths takes a params object as an argument.

client

Same as useGetStaticProps

type

Same as useGetStaticProps

apiParams

Same as useGetStaticProps

formatPath

function (required)

Function to format the path object that must be returned from getStaticPaths in Next.js. Pass null to skip. Defaults to (doc) => null. Example:

formatPath: (prismicDocument) => {
return {
params: {
uid: prismicDocument.uid
}
}
}

Hook example only

In the example below, we will create paths for a repeatable page type from the uid in the recently queried Prismic document.

See a full-page example further down the article.

  • [uid].js (dynamic file name)
  • Deprecated method (Before V0.1.0)
Copy
import Prismic from '@prismicio/client'
import { useGetStaticProps, useGetStaticPaths } from "next-slicezone/hooks";

// Fetch content from prismic
export const getStaticProps = useGetStaticProps({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  type: 'page',
  apiParams({ params }) {
    // params are passed by getStaticPaths
    return {
      lang: params.lang,
      uid: params.uid
    }
  }
})

// fetch all docs of type `page` and pass params accordingly
export const getStaticPaths = useGetStaticPaths({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  type: 'page',
  formatPath: (prismicDocument) => {
    return {
      params: {
        lang: prismicDocument.lang,
        uid: prismicDocument.uid
      }
    }
  }
})
Copy
export const getStaticPaths = useGetStaticPaths({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  type: 'page',
  formatPath: ({ uid }) => ({ params: { uid } })
})

<SliceZone />

Once slices have been fetched, they must be matched with Next.js components and rendered. The SliceZone accepts data from the API (fetched by useGetStaticProps) as a prop. It also accepts a resolver, which defines how to match Prismic Slices with Next.js components.

slices

array (required)

The data components fetched from Prismic

resolver

function (required)

Resolves calls to components from the SliceZone

sliceProps

object || function

This allows you to pass props, like for Theme UI, to have more control of a globally available component on the page level.

Example:

Here's an example of a [uid].js file with a Slice Zone component that is receiving Slices, custom props for Theme UI and we've imported the sm-resolver.js to pass to the SliceZone component.

Copy
import Prismic from '@prismicio/client'
import SliceZone from 'next-slicezone'
import { useGetStaticProps, useGetStaticPaths } from "next-slicezone/hooks";
import resolver from '../sm-resolver'

const Page = ({ slices, data }) => (
  <SliceZone
    slices={slices}
    resolver={resolver}
    sliceProps={({ slice, sliceName, i }) => ({
      theme: i % 1 ? "light" : "dark",
      alignLeft: data.keyTextTitle?.length > 35,
    })}
  />
)


export const getStaticProps = useGetStaticProps({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  apiParams({ params }) {
    return {
      uid: params.uid,
    }
  }
})

export const getStaticPaths = useGetStaticPaths({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  formatPath: (prismicDocument) => {
    return {
      params: {
        uid: prismicDocument.uid,
      }
    }
  }
})

export default Page

Examples

Take a look at the different use cases where you can make use of the SliceZone and the Lifecycle hooks.

Query by single type

In this example, we query a Singleton page of type "homepage" in an index.js file:

Copy
import Prismic from '@prismicio/client'
import SliceZone from 'next-slicezone'
import { useGetStaticProps } from 'next-slicezone/hooks'
import resolver from '../sm-resolver' // import from project root

const Page = ({ slices }) => (
  <SliceZone resolver={resolver} slices={slices} />
)

export const getStaticProps = useGetStaticProps({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  type: 'homepage', 
  queryType: 'single'
})

export default Page

Query by repeatable type

In this example, we dynamically query the Repeatable pages of type "post" using the uid of each document in a [uid].js file:

Copy
import Prismic from '@prismicio/client'
import SliceZone from 'next-slicezone'
import { useGetStaticProps, useGetStaticPaths } from 'next-slicezone/hooks'
import resolver from '../sm-resolver' // import from project root

const Post = ({ slices }) => (
  <SliceZone resolver={resolver} slices={slices} />
)

export const getStaticProps = useGetStaticProps({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  type: 'post', 
  apiParams({ params }) {
    return {
      uid: params.uid
    }
  }
})

export const getStaticPaths = useGetStaticPaths({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  formatPath: (prismicDocument) => {
    return {
      params: {
        uid: prismicDocument.uid
      }
    }
  }
})

export default Post

Query dynamically by language

In this example, we query a default repeatable type "page" using the uid and lang based in a 〜/pages/[lang]/[uid].js file:

Copy
import Prismic from '@prismicio/client'
import SliceZone from 'next-slicezone'
import { useGetStaticProps, useGetStaticPaths } from 'next-slicezone/hooks'
import resolver from '../sm-resolver' // import from project root

const Page = ({ slices }) => (
  <SliceZone resolver={resolver} slices={slices} />
)

export const getStaticProps = useGetStaticProps({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  apiParams({ params }) {
    return {
      lang: params.lang,
      uid: params.uid
    }
  }
})

export const getStaticPaths = useGetStaticPaths({
  client: Prismic.client('https://your-repo-name.cdn.prismic.io/api/v2'),
  formatPath: (prismicDocument) => {
    return {
      params: {
        uid: prismicDocument.uid,
        lang: prismicDocument.lang,
      }
    }
  }
})

export default Page

Was this article helpful?
Not really
Yes, Thanks

Can't find what you're looking for? Get in touch with us on our Community Forum.