-
Notifications
You must be signed in to change notification settings - Fork 432
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
fix: portable text editor crash #6870
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
1 Ignored Deployment
|
1865e6a
to
e001835
Compare
No changes to documentation |
Component Testing Report Updated Jun 7, 2024 8:31 AM (UTC)
|
88aaa8c
to
9e81d00
Compare
9e81d00
to
1f64bfb
Compare
e001835
to
e6ca596
Compare
e6ca596
to
5c4869b
Compare
5c4869b
to
435e4fc
Compare
useEffect(() => { | ||
console.warn( | ||
'useColorScheme() is deprecated, use useColorSchemeValue() or useColorSchemeSetValue() instead', | ||
) | ||
}, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The @deprecated
TSDoc haven't been sufficient to discourage using this hook, which is why it makes sense to console.warn
in useEffect
to push for possible userland to refactor away 🙌
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be nice to have another boolean outside this to prevent it from being logged more than once in cases where it's used in multiple components but more warnings means more annoying which may be more motivating lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm in favor of only logging once when it's not actionable. I'm this case the migration is very easy to do and I'd like to encourage it as much as possible 😬
435e4fc
to
62666c8
Compare
I'm curious, what was the actual culprit and what change fixed the issue? |
62666c8
to
f39f42e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
amazing work. the <Code>
change i’m curious about. lmk what u think!
@@ -115,6 +115,7 @@ function DocumentPaneInner(props: DocumentPaneProviderProps) { | |||
t={t} | |||
i18nKey="panes.document-pane.document-not-found.text" | |||
values={{id: options.id}} | |||
components={{Code: ({children}) => <code>{children}</code>}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why was this change introduced? i think the simple <code>
tag (lowercase) should be supported so ideally the translation strings should be refactored instead but i may be missing something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It crashed and complained about Code not being declared instead of showing the error. Then I saw a commit from @rexxars that fixed the same error but from a different location. Hang on let's see if I can find it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh hmm. I was referencing #5114
It's a bit tedious to pass in components like
<Code>
that just maps to<code>
. This PR allows using this predefined list of tags without specifying it directly:<abbr>
,<address>
,<cite>
,<code>
,<del>
,<em>
,<ins>
,<kbd>
,<q>
,<samp>
,<strong>
,<sub>
,<sup>
.
the suggestion is to change any translation string to remove <Code>
in favor of just <code>
instead of adding support for <Code>
but maybe we don't have control over those translation strings?
nbd though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, I have to admit I'm not too familiar with how our i18n works yet. All I know is that adding this line allowed the 404 to render again, instead of crashing the Structure Tool and propagating to the StudioErrorBoundary
that wraps the tool layout :D
useEffect(() => { | ||
console.warn( | ||
'useColorScheme() is deprecated, use useColorSchemeValue() or useColorSchemeSetValue() instead', | ||
) | ||
}, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be nice to have another boolean outside this to prevent it from being logged more than once in cases where it's used in multiple components but more warnings means more annoying which may be more motivating lol
const setValue = useContext(ColorSchemeSetValueContext) | ||
if (setValue === null) throw new Error('Could not find `ColorSchemeSetValueContext` context') | ||
return setValue | ||
} | ||
|
||
/** @internal */ | ||
export function _useColorSchemeInternalValue(): StudioThemeColorSchemeKey { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you think this hook needs to be exported? would refactoring it to not be exported be better? it seems like it was prefaced with an _ to prevent external usage but not exposing it does the same job
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be happy to do that in a quick follow-up! It's only needed internally so it doesn't need to be available on import 'sanity'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw the underscore caused the React Compiler to not see it as a hook, causing hook re-ordering errors, which is why it was changed here 🙌
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to know 💡
@@ -38,8 +42,8 @@ export function FormBuilderInputErrorBoundary( | |||
* when there are no errors. | |||
* @internal | |||
*/ | |||
function ErrorCard(props: {error: unknown; onRetry: () => void}) { | |||
const {error, onRetry} = props | |||
function ErrorCard(props: {error: unknown; info?: React.ErrorInfo; onRetry: () => void}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just double checking but is React.ErrorInfo available in the react 18 types as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup! We don't use React 19 types yet, and we might not do so before we drop 18 support, depending on wether it'll be possible to use both (framer-motion tried but couldn't get it to work, we'll see once 19 is stable and the new typings are available on
@types/reactinstead of the temporary
types-react@rc`) 🙌
@@ -22,14 +23,17 @@ export function FormBuilderInputErrorBoundary( | |||
props: FormBuilderInputErrorBoundaryProps, | |||
): JSX.Element { | |||
const {children} = props | |||
const [{error}, setError] = useState<{error: unknown}>({error: null}) | |||
const handleRetry = useCallback(() => setError({error: null}), []) | |||
const [{error, info}, setError] = useState<{error: unknown; info: React.ErrorInfo}>({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stylistic comment: since you made info optional in the ErrorCard, would it be better for info
here to be optional as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The typings from ErrorCard
in @sanity/ui
claims that it's always provided, so I follow that assumption here to ensure default values and reset values fulfill that contract.
It's optional in the component as a defensive measure, to ensure that should the component in @sanity/ui
somehow return null
or undefined
then the ErrorCard makes sure to account for it. I don't think it's likely to happen, but given that this component is supposed to handle unhandled runtime exceptions it felt reasonable to follow Murphy's Law
</Stack> | ||
</Box> | ||
)} | ||
{isDev && componentStack && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
really nice dev quality of life improvement here 💖
packages/sanity/src/core/form/inputs/PortableText/hooks/usePortableTextMembers.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice refactor!
Responded to this in depth on slack, the TL;DR is that writing to the ref in |
Description
On React 19 the Portable Text Editor sometimes ends up in an infinite render loop when there's no value yet, as demonstrated here: https://test-compiled-studio-b8mfdmi85.sanity.build/test/structure/input-standard;portable-text;pt_allTheBellsAndWhistles;7455ba88-75d5-4a77-94a4-91738fa670c5
This PR fixes it: https://test-compiled-studio-git-fix-portable-text-editor-crash.sanity.build/test/structure/input-standard;portable-text;pt_allTheBellsAndWhistles;7455ba88-75d5-4a77-94a4-91738fa670c5
The PR also contains a lot of other minor fixes related to React Compiler, improvements to how the color scheme state is passed around, adding the React Component stack to the form input error boundary etc.
What to review
There shouldn't be any infinite render recursion loops happening in React 19 anymore for Portable Text Editor, try and break it 🙌
Testing
Beyond manual testing the existing e2e testing suite should be enough.
Notes for release
Fixed React 19 causing Portable Text Editor to crash in some scenarios.