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

Invalid Hook Call #108

Open
mckelveygreg opened this issue Dec 20, 2023 · 5 comments
Open

Invalid Hook Call #108

mckelveygreg opened this issue Dec 20, 2023 · 5 comments

Comments

@mckelveygreg
Copy link
Contributor

Expected Behavior

To be able to use 3rd party libs that may have react hooks in them (ie useMemo for performance concerns in a browser)

The library that alerted me to this is, @portabletext/react and their component PortableText. This enables us to render rich text from our CMS into emails.
This code was able to run in the original react-email, but I'm unsure of how the library has shifted in this respect since then.

Actual Behavior

Throws Invalid Hook Call errors during the jsxToString function call

Additional Information

stack trace

chunk-I7UPNA6J.js?v=83f9a7a2:3509 Uncaught TypeError: Cannot read properties of null (reading 'useMemo')
    at useMemo (chunk-I7UPNA6J.js?v=83f9a7a2:3509:29)
    at ThirdPartyUseMemo (Reproduction.tsx?t=1703115101276:2146:16)
    at jsxToString (jsx-email.js?v=bf6a5f6d:24773:26)
    at jsxToString (jsx-email.js?v=bf6a5f6d:24766:24)
    at jsxToString (jsx-email.js?v=bf6a5f6d:24773:14)
    at jsxToString (jsx-email.js?v=bf6a5f6d:24725:22)
    at async jsxToString (jsx-email.js?v=bf6a5f6d:24766:18)
    at async render (jsx-email.js?v=bf6a5f6d:25206:15)
    at async main.tsx:67:16
    at async Promise.all (jsxemailrepro9a6jzc-exbx--55420--a2aabdd9.local-credentialless.webcontainer.io/index 0)
useMemo @ chunk-I7UPNA6J.js?v=83f9a7a2:3509
ThirdPartyUseMemo @ Reproduction.tsx?t=1703115101276:2146
jsxToString @ jsx-email.js?v=bf6a5f6d:24773
jsxToString @ jsx-email.js?v=bf6a5f6d:24766
jsxToString @ jsx-email.js?v=bf6a5f6d:24773
jsxToString @ jsx-email.js?v=bf6a5f6d:24725
Show 5 more frames
Show less
@shellscape
Copy link
Owner

Generally speaking, hooks aren't supported (right now). That's because email templates aren't interactive, and hooks are only really useful in interactive/reactive components that require hydration. While you might have an interactive/reactive component re-use use-case, they're really not a good fit for email templates because at the end of the day, email template outputs are static.

Immediate options for getting you past this:

  • use props with values coming from the parent component, or the component or code which is calling render (even if that's the CLI - you can use --props)
  • pass children in as props. (if not using the CLI)

I'll take a look at what it would take to support hooks, but it's important to understand what jsx-email (and even react-email and mjml) are actually providing to you - it's not a react app, it's a static file template engine with sugar to make the task easy.

@mckelveygreg
Copy link
Contributor Author

I understand this isn't a React app, and I don't expect state or anything, but this is a third party lib that turns rich text into DOM.

Looks like I should try to find an alternative method from that lib.

@shellscape
Copy link
Owner

This particular error seems to be common, with a common cause. Going to investigate a little bit on my end to see if our bundle may be to blame.

@shellscape
Copy link
Owner

So investigating this actually surfaced a few issues that will result in improvements, but none that are directly related to this issue unfortunately. There were dual versions of react within the bundled template (which is output to a temp directory); one in the bundled template, and one in node_modules for the project itself. That's resolved. The bundling of the email templates are actually faster now since it's excluding jsx-email and react. That took the bundled file size for a template from 7mb to 25kb. So that's fun. But again, won't resolve this issue.

This is probably related to react's internal dispatcher but not quite sure yet what the deal is there.

@mckelveygreg
Copy link
Contributor Author

Whelp, found a work around for this!
If I just render the react to html myself, then everyone is happy 🤷

import { PortableText } from "@portabletext/react"
import { renderToString } from "react-dom/server"

export const Template = () => {
  const html = renderToString(
    <PortableText
      value={body.filter(isTypedObject)}
      components={dynamicComponents}
      onMissingComponent={onMissingComponent}
    />
  )
return (
  <div dangerouslySetInnerHTML={{
                __html: html,
              }}
           />
 )
}

So I guess we could close? 🤷

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

2 participants