This is a simplification on my scenario
import React, { useState } from 'react';
import dynamic from 'next/dynamic';
const DynamicImportedComponent = dynamic(() => import('Foo/baz'), {
ssr: false,
loading: () => <p>loading..</p>
});
const MyComponent: React.FC = () => {
const [show, setShow] = useState(false)
const variableComponent = <SomeStyledComponent styled={show}>value of show is {show.toString()}</SomeStyledComponent>
return (
<>
{variableComponent}
{ show && <DynamicImportedComponent />}
<button onClick={() => setShow(!show)}>toggle</button>
</>
)
}
There is a toggle state that allows me to show or not a component that is dynamically loaded
I have a component that renders always, but based on the toggle might show different styles.
When the user clicks the button, the state sets to true and the component is dynamically loaded. In the meantime, nextjs render the loading message. So far, so good
However, I'd like the variableComponent
to be invisible while the DynamicImportedComponent
is being loaded. This is because it has some styles that don't quite look good with the loader. Is there a way to detect if the component has finished loading? Once the component is loaded, I would render the variableComponent
as I would normally do
I was thinking of something along the lines of
{(DynamicImportedComponent.loaded || !DynamicImportedComponent.isLoading) && variableComponent}
but that does not seem to exist.
I'm using latest version of React and nextjs, and typescript
I also ran into this issue. At the moment there isn't a standard way of doing this, but one of the Nextjs maintainers suggested the following in a discussion in the Nextjs repo:
We mirror React.lazy as much as possible (while also providing the missing loading state as suspense doesn't work server-side). Suspense might solve your case as it allows for a spinner to be shown for a part of the tree when one item suspends (eg the dynamic component). However as said Suspense is not available server-side currently.
One thing that you could potentially do is pass state in a context value and setState in the loading component
I found that the suggestion of using React Context works well.
const ToolbarTray: FunctionComponent<{}> = () => {
const { isDialogOpen, closeDialog, openDialog } = useDialogState();
const [ isDialogLoading, setDialogLoadingStatus ] = useState(false);
return (
<DynamicLoadingContext.Provider value={setDialogLoadingStatus}>
<Button onClick={openDialog}>
{isDialogLoading ? <CircularProgress /> : <EditIcon />}
</Fab>
{isDialogOpen && <EditPersonDialog onClose={closeDialog} />}
</DynamicLoadingContext.Provider>
);
};
const EditPersonDialog = dynamic(() => import('~/dialogs/edit-person-dialog'), {
ssr: false,
loading: () => {
const setLoading = useContext(DynamicLoadingContext);
useEffect(() => {
setLoading(true);
return () => setLoading(false);
}, [setLoading]);
return null;
},
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With