Open zioth opened 4 years ago
Hey @zioth this is interesting I haven't really dug into suspense yet, however I have a couple ideas on how to fix it using a combination of tricks to detect whether the element is visible (https://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom) and possible a MutationObserver in order to avoid polling. If you wanted to help, you could give me a repro by forking this pen: https://codepen.io/bsidelinger912/pen/zBgwmd. Otherwise I'll take a look when I can, it seems pretty straight forward.
I looked into MutationObserver, but you'd have to observe every parent node, and possibly refresh observers based on changes to the ReactDOM. Fortunately, my polling algorithm never ran more than once. If you find a reliable and efficient way to do it without any polling, I'd be very interested.
@zioth I can't seem to reproduce this. I'm lazy loading with suspense and set my network to mimic slow 3G with dev tools, that allows me to see the fallback component consistently for a decent amount of time but shiitake renders correctly for me every time, and I tried a bunch of time because it seems intermittent. Any tips on reproducing?
I never tried to make the minimum reproducible case. We use Shiitake for two UIs. One failed intermittently (and very rarely), and one failed every time. In both cases, I'm loading the page from my local machine, so network speed probably isn't a factor. The one big difference I see on the consistent failure page is that the JS chunk is pre-loaded (using javascript_pack_tag
-- this is a Rails app).
Another difference is that in the intermittent failure, the component is very small (Shiitake is only a few levels deep in the ReactDOM), while in the consistent failure, it's much larger.
I just tried to find the minimum reproducible case. It looks something like this:
// Located in lazy chunk #1
const MyComponent = () =>
<React.Fragment>
<Shiitake lines={2}>Hello2</Shiitake>
<OtherComponent/>
</React.Fragment>;
// Located in lazy chunk #2
const OtherComponent = () => '';
Shiitake
consistently renders with a height of 0px.
My other failure case is intermittent, so I can't reduce it to a reproducible case, but both cases seem to be fixed by polling offsetParent
to wait for Shiitake to be visible.
If you lazy-load a component including a
Shiitake
, the content sometimes doesn't render. This isn't your fault; it's due to a design flaw in React that the developers have said they aren't going to fix. Here's why it happens:display: none
on the topmost element. While this is happening, theSuspense
fallback is being displayed.display: none
, the measured height is zero.Suspense
fallback, and removesdisplay: none
. This action is not linked to the React lifecycle, and doesn't fire any sort of event, so there's no way to detect that this is happening.Shiitake
rerender by resizing the window or something, the content is rendered inside aheight: 0
element, which makes it invisible to the user.In my project, I worked around the issue by creating a wrapper component around
Shiitake
which goes up the DOM tree looking fordisplay: none
, and polling for that style's removal. It's very hacky, but it works.If you fix this, you'll have the only popular line-clamping component which can safely be lazy-loaded. I checked the others. :) If you like, I can ask my boss whether my workaround can be open sourced so you can use it as a dependency.