-
-
Notifications
You must be signed in to change notification settings - Fork 129
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
Convert the React bootloader to TypeScript #5961
Conversation
type GeneratorFunc = (data: any, elem: HTMLElement) => JSX.Element | ||
type Mappings = Record<string, GeneratorFunc> | ||
|
||
type TurboFrameRenderDetail = { |
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 couldn't find @types for turbo, so inferred this from its usage.
import { ExercismTippy } from '../components/misc/ExercismTippy' | ||
import { ReactQueryCacheProvider } from 'react-query' | ||
|
||
type ErrorBoundaryType = React.ComponentType<any> |
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.
Once updated to React 18, hopefully I can get rid of the any
here
} | ||
|
||
export function renderComponents( | ||
parentElement: HTMLElement = document.body, |
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.
changed all
if (!parentElement) {
parentElement = document.body
}
to default parameters
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.
Isn't that changing the behavior though? Previously, these calls would end up with parentElement
being set to document.body
, but they won't anymore:
renderComponents(null, ...)
renderComponents(undefined, ...)
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.
@dem4ron Did you see this comment?
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.
In our case this doesn't change the behaviour, because we don't pass in falsy values.
I made sure things wouldn't fail, by passing in a default parameter a level above too, which used to be simply undefined
- const renderThings = (parentElement) => {
+ const renderThings = (parentElement = document.body) => {
renderComponents(parentElement, mappings)
renderTooltips(parentElement, mappings)
}
// This adds rendering for all future turbo clicks
document.addEventListener('turbo:load', () => {
renderThings()
})
...
Another place where renderComponents
is used is in LazyTippy.tsx
:
export const LazyTippy = (props: LazyTippyProps): JSX.Element => {
const { renderReactComponents, ...tippyProps } = props
const [mounted, setMounted] = React.useState(false)
const lazyPlugin = {
fn: () => ({
onMount: () => setMounted(true),
onHidden: () => setMounted(false),
onAfterUpdate: (instance: Instance) => {
if (renderReactComponents) {
renderComponents(instance.popper, mappings)
}
},
}),
}
In the worst-case scenario here, the value would be undefined
too
On the other hand - given how mission critical this code is - I'm leaning towards reverting these changes to the input validation approach, because that is significantly more robust.
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.
But here:
const renderThings = (parentElement = document.body) => {
renderComponents(parentElement, mappings)
renderTooltips(parentElement, mappings)
}
I'd just pass in document.body
:
const renderThings = () => {
renderComponents(document.body, mappings)
renderTooltips(document.body, mappings)
}
export function initReact(mappings: Mappings): void {
const renderThings = () => {
renderComponents(document.body, mappings)
renderTooltips(document.body, mappings)
}
// This adds rendering for all future turbo clicks
document.addEventListener('turbo:load', () => {
renderThings()
})
// This renders if turbo has already finished at the
// point at which this calls. See packs/core.tsx
if (window.turboLoaded) {
renderThings()
}
}
Co-authored-by: Aron Demeter <66035744+dem4ron@users.noreply.github.com>
} | ||
|
||
export function renderComponents( | ||
parentElement: HTMLElement = document.body, |
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.
Isn't that changing the behavior though? Previously, these calls would end up with parentElement
being set to document.body
, but they won't anymore:
renderComponents(null, ...)
renderComponents(undefined, ...)
} | ||
} | ||
|
||
let ErrorBoundary: ErrorBoundaryType = () => <></> |
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.
@ErikSchierboom here
This PR turns
react-bootloader.jsx
intoreact-bootloader.tsx
inutils
.