Open Draecal opened 1 year ago
I am having the similar error. The error on the terminal says "cannot set property of jsx". Anything new?
I am running into the error as well when I try to use signals in a Nextjs13 project. When 'reactStrictMode' is set to false, signal seems able to continue working even with the error. Not sure if it is Next specific, but the issue was not observed in React projects.
Spent a bit time on it today, and found out the error likely related to Next.js's pre-rendering feature (https://nextjs.org/learn-pages-router/basics/data-fetching/pre-rendering). Pre-rendering happens at build time (for production) or at each page request (for development). I've confirmed the error doesn't show up at build time if I replace 'next build' with 'next experimental-compile' which is a new command that skips the pre-rendering step. I didn't see this error either when I took dynamic import approach with { ssr : false } option for a component including signals.
So basically don't use signals in nextjs. Sad
I don't think there's any need for signals to hook into React for SSR, since the state will never change server-side. Therefore, it should be enough (🤞) for signals-react to not call installJSXHooks
: https://github.com/preactjs/signals/blob/main/packages/react/runtime/src/auto.ts#L339
Unfortunately, I don't know enough about either Signal's or Next's codebase to make that happen.
To help people googling find this issue, here's my error: TypeError: Cannot set property jsx of [object Module] which has only a getter
Related: vercel/next.js/issues/45054
Added a workaround to that issue.
Thanks. I tried the workaround and it does the job. But I am seeing a side-effect that it voids the rendering optimization features of Signals, i.e., those components that are not subscribing to a signal would be also re-rendered when the signal value changes 😞
Try the library I just published on npm (signals-react-safe), it fixes the re-rendering issue.
@JonAbrams, thanks for the fix, it was quick.👍 Yeah, it is working most of the part now: the original error is gone ✔️, and only text node is updated when signal updates without re-rendering the component✔️. The only remaining one is when signal passed into a component as prop, the component doesn't get re-rendered (if referring to signal value in text node) when signal updates; referring to signal works though. Sorry, I am new to React/Next/Signals, maybe I missed anything? Anyway, the library with the fix provides pretty much everything of Signals I need for Next. Thanks again!
To have the component re-render when a signal updates, use the
useSignalValue
hook I added.
Works like a charm! 👍
Or just add "use client"
at the top of the file that imports the signal.
To have the component re-render when a signal updates, use the
useSignalValue
hook I added.
I tried to use this in a nextjs page without luck. The signal I want to use is to hold the current lang value
// useI18n.tsx
import { signal, useSignalValue } from 'signals-react-safe'
export const language = signal<Languages>('en') // I export a signal here
// the translate fn just return a json object
export const useI18n = () => {
return translate(languages[useSignalValue(language)])
}
// app/events/page.tsx
import React from 'react'
import { useI18n } from '@/app/ui/hooks/useI18n'
const Page = () => {
const t = useI18n()
return (
<section>
{t('CREATE_EVENT')}
</section>
)
}
export default Page
The error when this page renders on the server:
node_modules/signals-react-safe/dist/index.mjs (15:37) @ signal2
⨯ useState only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component
at useI18n (./app/ui/hooks/useI18n.tsx:28:98)
at Page (./app/events/page.tsx:18:77)
at stringify (<anonymous>)
Under the hood useSignalValue
uses useState
. So it means you can only use it in client components. I should look into if it's possible to avoid using useState in server components to fix this.
Actually, it turns out you're not supposed to use hooks in server components. Instead, access the signal and/or it's value directly in the server component. Since server components don't re-render, it should be safe.
In the future, please raise an issue with the signals-react-safe
library here.
e.g.
import { language } from '../mySignals';
const Page = () => {
const t = translate(languages[language.value]);
return (
<section>
{t('CREATE_EVENT')}
</section>
)
}
it seems like you guys seeing this error at the server side component, but I use it literally at client side components but not with the props drilling way, just the export and import way, and the error occurs...
The error appears to stem from trying to patch React.createElement
.
There seems to be some inconsistent behavior on webpack module resolution with ES module interop in how import React from 'react'
or import * as React from 'react'
is converted to require('react')
calls. The same is true for the runtime JSX module patching.
We've noticed our patching of React.createElement
started failing with the same error shown in original post in next@14
. I managed to workaround that by patching like
(React.default || React).createElement = wrap(React.createElement);
or
Object.assign(React.default || React, {createElement: wrap(React.createElement)});
This is a problem related with monkeypatching from @preact/signals-react
versions 1.x.x. Now you can use babel plugin (but not all feature of next.js working with it). Alternatively - you can @preact-signals/safe-react
with swc plugin
Error:
Cannot set property createElement of [object Module] which has only a getter
Environment:
Code:
Expected:
At least the app to load, instead receiving the error described.
Tried all approaches possible, even the documentation examples within my environment.