0

I'm working on a React app using typescript and loadable components (for SSR implementation) and trying to implement a placeholder for a loadable component to reduce shifting of the page on initial load (the page loads first, after a few seconds the loadable component appears, shifting things down). I have tried to use the loadable components fallback property, but that causes even more shift (fallback takes a bit to appear, disappears collapsing the space where it was, then loadable component appears).

I was thinking then to use a hook to load this component but I'm having error after error. I was wondering if using loadable component inside an useEffect is possible at all? Also, how to use the module that is returned from loadable(() => import('/someModule')) ? Just using it normally like is not working.

I can usually load the loadable component like this:


const Module = loadable(() => import('./SomeModule'));

<Module /> // ---> usage

And have tried this following function to have a placeholder in its place while it's loading:

const useLazyContainer = (): any => {
  const Fallback = () => <div style={{ minHeight: '200px' }}>Loading</div>;
  const [component, setComponent] = useState<any>(Fallback);

  useEffect(() => {
    (function loadComponent() {
      const Module = loadable(() => {
        import('./Module');
      });

      setComponent(Module);
    })();
  }, []);

  return component;
};

Then using it:

const SomeComponent = useLazyContainer();

return (
     <div>
       {SomeComponent}
    </div>. 
)

But then, I get error:

Uncaught Error: Objects are not valid as a React child (found: object with keys {$$typeof, render, preload, load}). If you meant to render a collection of children, use an array instead.

It seems the type of module is this {$$typeof: Symbol(react.forward_ref), render: ƒ, preload: ƒ, load: ƒ} but React is refusing to render it.

I also tried invoking SomeComponent as

Does anyone have any ideas about how to get this working or if it's even possible?

JBird
  • 121
  • 1
  • 8

1 Answers1

0

In the end I found out if I wanted to recreated the fallback logic I could do this:

const MyComponent = loadable(() => import('stuff'));

const MyApp = () => {
 const [loaded, setLoaded] = useState(false);
 useEffect(() => MyComponent.preload().then(() => setLoaded(true)), []);

 return loaded ? <MyComponent /> : <div>loading...</div>
}

But that didn't help with page shift. What helped was actually just wrapping the loadable components in a wrapper div with min-height.

<div style={{minHeight: '200px'}}>
    <MyLoadableComponent>
</div>
JBird
  • 121
  • 1
  • 8