Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The provider should be on wrapRootElement instead of wrapPageElement #116

Closed
viniciusflv opened this issue May 12, 2020 · 6 comments
Closed

Comments

@viniciusflv
Copy link

viniciusflv commented May 12, 2020

First of all, I would like to congratulate the team for this plugin. It is simple, stable and intuitive.

I just have one problem with it. I assumed the provider was injected into a wrapRootElement, which makes sense to me.

But when I tried to use it in the wrapPageElement, I realized it wasn't.

Any change to the change from wrapPageElement to wrapRootElement. Or at least give the developer the choice?

I believe it is not even a breaking change and would help me a lot.

thank you

@samajammin
Copy link
Contributor

samajammin commented May 15, 2020

I think this is related to my issue but not sure.

This plugin has been working great for all my page components & componets within pages but I just tried using FormattedMessage in my nav.js component (which is used within my layout.js), I see this error:

invariant.js:4 Uncaught Error: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.

I'm guessing this is because the <IntlProvider> is only used to wrap page elements (via wrapPageElement) vs. wrapping the root element (via wrapRootElement )?

@viniciusflv
Copy link
Author

viniciusflv commented May 15, 2020

My work around is using the loadPageSync from wrapRootElement.

  export const wrapRootElement = ({
    element,
    ...props // loadPageSync
  }: WrapRootElementBrowserArgs | WrapRootElementNodeArgs) => {
    return <App {...props}>{element}</App>;
  };

So, I get the data to add another provider to use the changeLocale trigger on my layout component.

  export const App: FC<any> = memo(({ loadPageSync, children }) => {
    const [locale, setLocale] = useState('');
    const [defaultLocale, setDefaultLocale] = useState('');
    const [messages, setMessages] = useState({});

    useEffect(() => {
      const {
        json: {
          pageContext: { intl, language },
        },
      } = loadPageSync(window?.location?.pathname);

      setLocale(language);
      setDefaultLocale(intl.defaultLanguage);
      setMessages(intl.messages);
    },        []);

    return (
      <IntlProvider
        locale={locale}
        defaultLocale={defaultLocale}
        messages={messages}
      >
        <Theme>
          <SEO />
          {children}
          <GlobalStyle />
        </Theme>
      </IntlProvider>
    );
  });

@samajammin
Copy link
Contributor

Thanks @viniciusflv! I appreciate the help. I ended up going with a similar but different solution.

I already had this wrapPageElement:

export const wrapPageElement = ({ element, props }) => {
  return <Layout {...props}>{element}</Layout>
}

& realized my <Layout/> component received the intl object as props, so similar to you I created a provider to wrap my component:

render() {
    const intl = this.props.pageContext.intl
    return (
      <IntlProvider
        locale={intl.language}
        defaultLocale={intl.defaultLocale}
        messages={intl.messages}
      >
       ...
      </IntlProvider>
    )
  }
}

Now I'm able to import & use FormattedMessage in my <Nav/> component 🎉.

While this works, I am curious to hear from @wiziple if this is the recommended approach for this situation. Thanks in advance!

@bartosjiri
Copy link

+1

This is obstructing the usage of Framer Motion's <AnimatePresence /> component for layout transitions, e.g. skipping the unmount animations.

@jdahdah
Copy link

jdahdah commented Dec 3, 2020

I'm really struggling to get either of these solutions working. Would it be possible for someone to show a working example of how to implement either wrapRootElement or wrapPageElement based on the example starter?

I keep running into this issue:

TypeError: Cannot read property 'language' of undefined
(anonymous function)
node_modules/gatsby-plugin-intl/link.js:27
  24 |     onClick = _ref.onClick,
  25 |     rest = (0, _objectWithoutPropertiesLoose2.default)(_ref, ["to", "language", "children", "onClick"]);
  26 | return _react.default.createElement(_intlContext.IntlContextConsumer, null, function (intl) {
> 27 |   var languageLink = language || intl.language;
  28 |   var link = intl.routed || language ? "/" + languageLink + to : "" + to;
  29 | 
  30 |   var handleClick = function handleClick(e) {

@omeid
Copy link

omeid commented Aug 23, 2023

Changing to wrapRootElement would also allow using intl with Gatsby's new Head API.

Please consider reopening this issue @wiziple.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants