@stnew/prismic-react
TypeScript icon, indicating that this package has built-in type declarations

1.2.6 • Public • Published

@stnew/prismic-react

@stnew/prismic-react has peerDepenendencies of react and react-dom. This package assumes you have a basic React app running and have set up the Prismic client.

This package exports:

PrismicContext

For the most part, you'll want to use the usePrismic hook to access context. If not, it's exported from the package main:

import { PrismicContext } from '@stnew/prismic-react'

function Consumer() {
  return (
    <PrismicContext.Consumer>
      {value => /* render something based on the context value */}
    </PrismicContext.Consumer>
  )
}

PrismicProvider

In order for @stnew/prismic components to work, you'll need to wrap your App in PrismicProvider and pass a few props.

// _app.js
import { PrismicProvider } from '@stnew/prismic-react'
import { sliceMap } from 'slices'
import { routeMap } from 'lib/prismic/routes'
import { elementsMap } from 'lib/prismic/rich-text'

function App({ Component, pageProps }) {
  return (
    <PrismicProvider
      sliceRegistry={sliceMap}
      urlResolver={routeMap}
      htmlResolver={elementsMap}
    >
      <Component {...pageProps}>
    </PrismicProvider>
  )
}
Prop Required Type
sliceRegistry No { [key: string]: (props: any) => Element }
urlResolver No Routes object
htmlSerializer No { [Element]: [React.ReactNode, { ...props }]

Pass the sliceMap and routeMap to their respective props. See the HTML Serializer section to learn more it's usage.

SliceZone

The SliceZone component will render slices from Prismic.

When you query Prismic's REST API, you'll get back a data object that contains all the fields you set up for that content type. The body property is a reserved key in Prismic, and it will contain all of your slices. Pass this to the data prop in SliceZone.

// pages/index.js
import { SliceZone } from '@stnew/prismic-react'
import { prismicClient } from 'lib/prismic'

function Page({ data }) {
  return (
    <main>
      <h1>{data.title}</h1>
      <SliceZone data={data.body} />
    </main>
  )
}

export async function getStaticProps() {
  const document = await prismicClient.getByUID('page', 'homepage')
  const { data } = document

  return {
    props: {
      data
    }
  }
}

sliceMap

Each Slice in data.body is an object with all of the slice data.

{
  "primary": {},
  "items": [],
  "slice_label": null,
  "slice_type": "slice_name"
}

In order for slices to be available to SliceZone, you'll need to setup a map of all your slices. The key is the slice_type, the value is your React component.

// slices/index.js
import { CoolSlice } from './CoolSlice'
import { GoodSlice } from './GoodSlice'

/**
 * @key slice_type
 * @value React Component
 */
export const sliceMap = {
  'cool_slice': CoolSlice,
  'good_slice': GoodSlice,
}

This map can be passed to <PrismicProvider>'s slices prop to make it available to all, or at the page level by passing it to <SliceZone>'s slices prop. If you have both, it will combine them, so you can have some slices that are global and some slices specific to each page. This helps diminish bundle size.

// Pass to PrismicProvider...
function App() {
  return (
    <PrismicProvider slices={sliceMap}>
      {...}
    </PrismicProvider>
}

// ... or pass to SliceZone...
function Page() {
  return <SliceZone data={data.body} slices={sliceMap}>
}

SliceZone will pass all of the slice data to each component as props.

function CoolSlice({ primary, items }) {

  const { title, sub_title } = primary

  return (
    <div>
      <h1>{title}</h1>
      <h2>{sub_title}</h2>
      {items.map((item, i) => (
        <p key={i}>{item.copy}</p>
      ))}
    </div>
  )
}

Code-Splitting

If your app has a ton of slices, including them on every single page can cause bloat. SliceZone lets you dynamically import components for smaller bundles.

// slices/index.js
const CoolSlice = import('./CoolSlice')
const GoodSlice = import('./GoodSlice')

export const sliceMap = {
  'cool_slice': CoolSlice,
  'good_slice': GoodSlice,
}

This also works with next/dynamic imports.

usePrismic

All of this magic is thanks to the usePrismic hook. You probably won't need this, but the hook will return everything from PrismicContext.

import { usePrismic } from '@stnew/prismic-react'

function Component() {
  const {
    sliceMap,
    linkResolver,
    hrefResolver,
    htmlSerializer,
  } = usePrismic()

  return <SliceZone slices={sliceMap} />
}

HTML Serializer

Using the serializer requires that you've installed prismic-reactjs. If you haven't, install with

npm install prismic-reactjs

Prismic's RichText field returns structured data that needs to be parsed to render as HTML. Wwile you could write your own parser, we recommend using the RichText component to render it instead.

import { RichText } from 'prsimic-reactjs'

function Page({ data }) {
  return (
    <main>
      <h1>{data.title}</h1>
      <RichText render={data.body_copy} />
    </main>
  )
}

The default RichText component will render pretty generic HTML. If you need to use special text components, add classNames and props, or render custom HTML, you'll need to write and HTML Serializer

Mapping the elements

The serializer accepts a special mapping

import { Elements } from 'prsimic-reactjs'
import Link from 'next/link'

const elementsMap = {
  [Elements.heading1]: ['h1', { className: 'heading-1' }],
  [Elements.heading2]: ['h2', { className: 'heading-2' }],
  [Elements.paragraph]: ['p', { className: 'paragraph' }],
  [Elements.hyperlink]: [Link, ({ data }) => { href: data.url }]
  [Elements.hyperlink]: ['img', ({ data }) => { href: data.src }]
}

You can then pass this map the the htmlSerializer prop

function App() {
  return (
    <PrismicProvider
      htmlSerializer={elementsMap}
      urlResolver={routeMap}
    >
      {...app}
    </PrismicProvider>
  )
}

The serializer will be returned by the usePrismic hook.

import { RichText } from 'prsimic-reactjs'

function TextField({ render }) {
  const { htmlSerializer, linkResolver } = usePrismic()
  return <RichText
    render={render}
    htmlSerializer={htmlSerializer}
    linkResolver={linkResolver}
  />
}

useHtmlSerializer

If you only need to use the HTML serializer in one component, you can use it as a hook.

import { RichText } from 'prsimic-reactjs'
import { elementsMap } from 'lib/prismic/rich-text'
import { linkResolver } from 'lib/prismic/resolvers'
import { useHtmlSerializer } from '@stnew/prismic-react'

function TextField({ render }) {
  const htmlSerializer = useHtmlSerializer(elementMap)

  return <RichText
    render={render}
    htmlSerializer={htmlSerializer}
    linkResolver={linkResolver}
  />
}

serializeElements

If you don't want to use a hook or provider, you can export the wrapper function that creates the serializer.

import { elementsMap } from 'lib/prismic/serializer'
import { serializeElements } from '@stnew/prismic-react'

const htmlSerializer = serializeElements(elementMap)

Readme

Keywords

none

Package Sidebar

Install

npm i @stnew/prismic-react

Weekly Downloads

1

Version

1.2.6

License

MIT

Unpacked Size

39.2 kB

Total Files

42

Last publish

Collaborators

  • artofrawr
  • ryanhefner
  • cabe
  • returningsam