RFC: @prismicio/react refresh
See original GitHub issueOverview
This request for comments (RFC) presents a collection of React components and hooks to make presenting and fetching Prismic content easy and extendable. Some of the described components are updates to the existing prismic-reactjs
library, while others are new.
These ideas have been developed as a result of real-world use in different environments including within agencies and in-house development teams.
The proposals defined in this RFC are designed for all React users. Some are general enough to be used in frameworks (such as Next.js and Gatsby), while others are recommended for non-framework use. Each section includes a “Designed to be used with” label to identify for whom it is designed.
Background Information
prismic-reactjs
currently includes the following exports:
Components
<RichText>
: Render a Rich Text field into React Components
Functions
RichText.asText()
: Convert a Rich Text field into a text stringDate()
: Parse a Date field into a Date objectLink.url()
: Convert a Link field into a URL
This API combines a React Component with a collection of helper functions from @prismicio/helpers
and @prismicio/richtext
. The combination of components and functions leads to non-idiomatic React code, mixing JSX (e.g. <RichText>
) with JavaScript expressions (e.g. {RichText.asText()}
).
Components provide a way to encapsulate functionality. The current library does not fully utilize this concept. Link.url()
, for example, could be integrated into a <Link>
component which performs the URL transformation implicitly. Because Link.url()
is simply a re-exported helper from @prismicio/helpers
, users could import that library instead if such lower-level functionality is needed.
Proposal
The following components and hooks make for a more robust React integration with Prismic.
<PrismicProvider>
: Central configuration.<SliceZone>
: Render Slices in a Slice Zone.<RichText>
: Render a Rich Text field into React Components.<RichTextAsText>
: Render a Rich Text field as text.<PrismicLink>
: Render a Link field as a router-specific Link or anchor element.<PrismicToolbar>
: Add the Prismic Toolbar script.usePrismicDocument()
, et al.: Prismic document fetching hooks.
Each component and hook is described below.
Rename to @prismicio/react
To mirror recent efforts to streamline Prismic’s library naming, the library should be renamed from prismic-reactjs
to @prismicio/react
.
The following Prismic libraries also follow this convention:
@prismicio/client
@prismicio/helpers
@prismicio/richtext
@prismicio/types
<PrismicProvider>
Designed to be used with: React w/o a framework, Next.js, Gatsby
This Context Provider sets up app-wide configuration for the library’s components and hooks. It can contain an app’s @prismicio/client
instance, Link Resolver, Rich Text components, and a router-specific Link component. See the following component and hook descriptions to learn how they are used.
Using the provider is optional. If it is not used, components and hooks can be configured where they are used.
In cases where multiple repositories are used to gather content, or when location-specific overrides are needed, values provided to the provider have a lower priority than configuration provided to a component or hook directly.
import * as prismic from '@prismicio/client'
import { PrismicProvider, PrismicLink } from '@prismicio/react'
import { Link } from 'react-router-dom'
import { linkResolver } from '../linkResolver'
import { Heading } from './Heading'
const endpoint = prismic.getEndpoint('qwerty')
const client = prismic.createClient(endpoint)
const richTextComponents = {
h1: 'h2',
h2: Heading,
h3: (props) => <Heading as="h4" {...props} />,
}
const App = ({ children }) => {
return (
<PrismicProvider
client={client}
linkResolver={linkResolver}
richTextComponents={richTextComponents}
internalLinkComponent={Link}
>
{children}
</PrismicProvider>
)
}
<SliceZone>
Designed to be used with: React w/o a framework, Next.js, Gatsby
See the dedicated <SliceZone>
RFC: https://github.com/prismicio/prismic-reactjs/issues/86
<SliceZone
slices={document.data.body}
components={{
foo: FooSlice,
bar: BarSlice,
}}
/>
<RichText>
Designed to be used with: React w/o a framework, Next.js, Gatsby
This component renders an HTML representation of a Rich Text field. It automatically converts links using a provided Link Resolver. By default, it renders a standard set of HTML elements (e.g. Heading 1 becomes <h1>
), but can be overridden using a list of components.
The component to be rendered can be provided in several ways:
- As a string denoting an HTML element (e.g.
"h2"
). - As a direct reference to a React component (e.g.
Heading
). - As an inline React component definition (e.g.
(props) => <Heading as="h4" {...props} />
)
This provides users an easy and flexible way to override the rendered components. This replaces the HTML Serializer concept with a simpler approach without removing capabilities.
<RichText
field={document.data.content}
linkResolver={linkResolver}
components={{
heading1: 'h2',
heading2: Heading,
heading3: (props) => <Heading as="h4" {...props} />,
hyperlink: (props) => <PrismicLink internalComponent={Link} {...props} />,
}}
/>
If <PrismicProvider>
is used and configured with a richTextComponents
prop, it will be used as <RichText>
's components
prop. If a components
prop is provided to <RichText>
, it will take priority over the prop provided to <PrismicProvider>
. The same behavior is included for linkResolver
.
<RichText field={document.data.content} />
<RichTextAsText>
Designed to be used with: React w/o a framework, Next.js, Gatsby
This component renders a text representation of a Rich Text field. It serves as the “non-rich” counterpart to the <RichText>
component as it strips all formatting and HTML representations within the field’s contents.
<RichTextAsText field={document.data.content} />
Since the output is a string, no customization aside from the field
prop is necessary.
<PrismicLink>
Designed to be used with: React w/o a framework, Next.js, Gatsby
This component renders a link from a Prismic Link field. It supports internal and external URLs and can render the appropriate component accordingly. If a link is internal to an app, the app may require a special <Link>
component to be rendered rather than an <a>
element. <PrismicLink>
will automatically switch to that component as needed.
<PrismicLink
field={document.data.link}
linkResolver={linkResolver}
internalComponent={Link}
externalComponent="a"
>
Learn More
</PrismicLink>
If the link is configured with target="_blank"
, which can be set within the Prismic editor, rel="noopener noreferrer"
will be added for improved security. Users can opt-out by providing their own rel
prop.
For <RichText>
and Gatsby compatibility, PrismicLink
can take an href
directly. The href
prop accepts a URL string that has already gone through the app’s Link Resolver or an external URL. The URL can be internal or external with the same automatic adaption described previously.
// Renders externalComponent
<PrismicLink href="https://example.com">
Learn More
</PrismicLink>
// Renders internalComponent
<PrismicLink href="/about">
Learn More
</PrismicLink>
If <PrismicProvider>
is used and configured with an internalLinkComponent
prop, it will be used as <PrismicLink>
's internalComponent
prop. If an internalComponent
prop is provided to <PrismicLink>
, it will take priority over the prop provided to <PrismicProvider>
. The same behavior is included for externalComponent
.
<PrismicLink field={document.data.link}>
Learn More
</PrismicLink>
<PrismicToolbar>
Designed to be used with: React w/o a framework, Next.js, Gatsby
This component makes it convenient to add the Prismic Toolbar to an app. It automatically generates the correct script URL and includes the recommended configuration.
<PrismicToolbar repositoryName="qwerty" type="new" />
The output would be equivalent to the following HTML.
<script
src="https://static.cdn.prismic.io/prismic.js?repo=qwerty&new=true"
defer="true"
/>
usePrismicDocument()
, et al.
Designed to be used with: React w/o a framework
A collection of React hooks, including usePrismicDocuments()
, usePrismicDocumentByID()
, and usePrismicDocumentsByType()
, queries the Prismic REST API for content from a Prismic repository.
The API mirrors that of the @prismicio/client
library in hook form. It handles different states automatically, such as loading states and data persistence between re-renders. API parameters, such as lang
and orderings
, are provided as each hook’s last parameter, just like using the client directly.
The following hooks fetch one or more documents. They return Prismic’s paginated API responses which can be helpful when displaying paginated content.
usePrismicDocuments()
usePrismicDocumentsByIDs()
usePrismicDocumentsByTag()
usePrismicDocumentsByTags()
usePrismicDocumentsByType()
The following list of hooks is a variation of the previous list. These hooks automatically fetch all documents from a paginated response and may make multiple network requests in order to fetch all matching documents.
useAllPrismicDocuments()
useAllPrismicDocumentsByIDs()
useAllPrismicDocumentsByTag()
useAllPrismicDocumentsByTags()
useAllPrismicDocumentsByType()
The following hooks return one document.
usePrismicDocumentByID()
usePrismicDocumentByUID()
useFirstPrismicDocument()
: Returns only the first matching documentuseSinglePrismicDocument()
: Returns a singleton document of a given type
All hooks return the following data shape:
import * as prismic from '@prismicio/client'
import { usePrismicDocument } from '@prismicio/react'
const endpoint = prismic.getEndpoint('qwerty')
const client = prismic.createClient(endpoint)
const MyComponent = () => {
const { data, isLoading, error } = usePrismicDocumentByUID('page', 'home', {
client
})
return <span>My component</span>
}
data
: The paginated API response or document, depending on the hook. During a loading state, this prop isnull
.isLoading
:true
when the hook is fetching data,false
otherwise.error
: The error if the query fails.
The @prismicio/client
instance is provided using the client
option in the hooks’ last parameter.
import * as prismic from '@prismicio/client'
import { usePrismicDocumentByUID } from '@prismicio/react'
const endpoint = prismic.getEndpoint('qwerty')
const client = prismic.createClient(endpoint)
const MyComponent = () => {
const { data, isLoading, error } = usePrismicDocumentByUID('page', 'home', {
client,
})
return <span>My component</span>
}
If <PrismicProvider>
is used and configured with a client
prop, it will be used as the client
option. If a client
option is provided to a hook, it will take priority over the prop provided to <PrismicProvider>
.
How to provide feedback
This is a public request for comments on the proposed ideas. If you have any feedback or suggestions, please feel free to reply below.
We would like to hear from potential users of these ideas whether the ideas positively or negatively impact workflows. If you have any additional ideas as well, please share them here.
Everything posted here is open for feedback and is not final. Development may have already begun by the time you are reading this, but please do not let that stop you from providing feedback.
Thank you!
A note on an image component
An image component is intentionally not included in this RFC. If such a component were to be included, it would perform the following:
- Progressive loading (including the “blur-up” technique)
- Automatic
srcSet
generation - Automatic aspect ratio sizing to prevent content reflows
Users using React as part of a framework, like Next.js or Gatsby, already have access to deeply integrated image components with those features. They are widely used and well tested with a dedicated team behind them.
Users using React directly, including those using Create React App, can use Imgix’s official React component, react-imgix
, with the same benefits.
As such, a <PrismicImage>
component is not included in the RFC. We can, however, provide proper integrations with React frameworks through gatsby-source-prismic
and @prismicio/next
(does not exist at the time of writing). We can also provide guidance for non-framework users.
If you feel this is not the correct approach, please comment below.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:4
- Comments:15 (12 by maintainers)
Top GitHub Comments
@prismicio/react@v2.0.0
was just published (see #97) so I’m going to close this issue.Thanks for your feedback, everyone! 🎉
@lihbr
document
is now a prop on<PrismicLink>
🎉 (https://github.com/prismicio/prismic-reactjs/commit/0768280e049d120cb93ebac581bc4e629ff98c67)