prismicio / prismic-react

React components and hooks to fetch and present Prismic content
https://prismic.io/docs/technologies/homepage-reactjs
Apache License 2.0
154 stars 40 forks source link

[Gatsby] `usePrismicContext` returns {} using `PrismicProvider` inside `wrapRootElement` API #107

Closed morellodev closed 2 years ago

morellodev commented 2 years ago

Versions

Description

I am adding a linkResolver function and a custom internalLinkComponent to the entire Gatsby website, putting the <PrismicProvider> inside the wrapRootElement (both in gatsby-ssr.js and in gatsby-browser.js). If I open the React devtools, I can see the PrismicProvider in the components tree, but every child that access the value exposed by it receives an empty object.

// gatsby-ssr.js and gatsby-browser.js

const React = require('react')
const { Link } = require('gatsby')
const { PrismicProvider } = require('@prismicio/react')

const linkResolver = require('./linkResolver')

exports.wrapRootElement = ({ element }) => {
  return (
    <PrismicProvider
      linkResolver={linkResolver}
      internalLinkComponent={({ href, children, ...otherProps }) => (
        <Link to={href} {...otherProps}>
          {children}
        </Link>
      )}
      externalLinkComponent={({ href, target, children, ...otherProps }) => {
        const targetProps = target ? { target, rel: 'noopener' } : {}
        return (
          <a href={href} {...otherProps} {...targetProps}>
            {children}
          </a>
        )
      }}
    >
      {element}
    </PrismicProvider>
  )
}

React devtools (<PrismicProvider>):

Schermata 2021-12-28 alle 13 15 58

React devtools (child accessing the PrismicContext):

Schermata 2021-12-28 alle 13 16 20
angeloashmore commented 2 years ago

Hi @morellodev, this happens because gatsby-browser.js/gatsby-ssr.js are using require() while your pages are likely using import.

Using require() will point at @prismicio/react's CommonJS file, while import will use its ESM file. Each file has its own React context object. usePrismicContext() from the ESM file cannot "see" the PrismicProvider from the CommonJS file.

You can fix this by writing your gatsby-browser.js/gatsby-ssr.js using ESM syntax:

// gatsby-ssr.js and gatsby-browser.js

import * as React from 'react'
import { Link } from 'gatsby'
import { PrismicProvider } from '@prismicio/react'

import linkResolver from './linkResolver'

export const wrapRootElement = ({ element }) => {
  return (
    <PrismicProvider
      linkResolver={linkResolver}
      internalLinkComponent={({ href, children, ...otherProps }) => (
        <Link to={href} {...otherProps}>
          {children}
        </Link>
      )}
      externalLinkComponent={({ href, target, children, ...otherProps }) => {
        const targetProps = target ? { target, rel: 'noopener' } : {}
        return (
          <a href={href} {...otherProps} {...targetProps}>
            {children}
          </a>
        )
      }}
    >
      {element}
    </PrismicProvider>
  )
}

If this doesn't fix your issue, let me know and I'll reopen the issue. Thanks! 🙂

morellodev commented 2 years ago

Thank you @angeloashmore, I will try your fix and eventually I will come back here again 😃

morellodev commented 2 years ago

It worked! Thanks a lot 👍

angeloashmore commented 2 years ago

Glad to hear it's working! 😀