lit: [labs/react]Using @lit-labs/react to wrap components in an SSR environment(Remix) will result in attributes not being immediately passed to the component
Which package(s) are affected?
React (@lit-labs/react)
Description
Attributes will pass to the components which wrapped by CreateComponent after about 500ms, it will make a obvious flash.
Reproduction
https://stackblitz.com/edit/remix-run-remix-nhexf3?file=app%2Fcomponent%2Fbutton.js
Workaround
Use components directly?
Is this a regression?
No or unsure. This never worked, or I haven’t tried before.
Affected versions
@lit-labs/react: 1.2.1; lit: 2.7.6;
Browser/OS/Node environment
node: v19.9.0 react: 17.x or 18.x
About this issue
- Original URL
- State: open
- Created a year ago
- Comments: 17 (11 by maintainers)
Could you consider using
firstUpdatedinstead ofconnectedCallback?I think part of it is that a well authored web component should be able to take “required” initial values it needs as attributes since that’s the only way to provide data with HTML. If it relies on properties, it should be written to be able to handle having it set later.
If we’re digging into the property options, I’d probably only consider setting attributes for those that have
reflect: true, and actually get the value for it based on the given JSX prop.The blanket fallback to attribute would definitely have to be opt-in as an option to
createComponentsince we would have no idea whether it’s even serializable.Hmm. The
@propertydecorators do have theattribute: booleanproperty that should give a hint about which fields can be set as attributes.There still could be a timing issue where all the attributes are set before the element is inserted into the DOM, which kicks off some work via connectedCallback() when the element is inserted, and then the properties are set changing the result/kicking off more work.
It does seem like falling back to attributes would be ok for most Lit elements because of the ease of creating serializers for props. However, it’s not really correct/semantic to set the attributes and properties in two phases.
I wonder if it could be opt-in through either a mapping object or boolean flag.
That’s definitely a valid concern. Currently with
@lit-labs/ssr-reactit’s possible that attributes would be inlined for reflecting properties when server rendered so initial render on the client will have it.Just brainstorming here, perhaps
createComponentcould take an array or set of attribute names that it will opt to provide to React to be set as attributes even if it’s found in the element class prototype. It puts the onus on the user to select which props are safe to be set as attributes rather than properties.This is a tricky situation to handle. The wrapper withholds props that are found in the element’s prototype so they won’t be set as attributes by React. This is normally desired for complex properties and works well on client rendering.
In SSR, React’s default server rendering has no knowledge of the internals of the custom element. We’ve tried to remedy this with
@lit-labs/ssr-reactto allow prop setting and attribute reflection during SSR, but haven’t tested with Remix. I tried a quick stab at applying it here https://stackblitz.com/edit/remix-run-remix-sttgwq?file=tsconfig.json. While it does SSR the custom element preventing flash from un-upgraded custom element to upgraded, it doesn’t seem to handle the props for the wrapped component. My guess is our method of monkey-patchingReact.createElementis not being detected, or Remix isn’t pulling in the Node build of@lit-labs/react.We’ll need to explore this further, possibly use a global flag for Lit SSR detection rather than monkey-patching
React.