Reputation: 2343
I am building websites with Gatsby and Contentful and it has been great so far. My problem is, that I don't know how to dynamically render components based on the data in Contentful.
Let's say there is a page content type which as a title, url and field for components. Those components could be a YouTube player, or markdown text or photos. Currently I'm using a custom component that imports all available components and then renders the components of the page using switch.
switch (contentType) {
case 'billboard':
return <Billboard key={key} id={key} {...section.fields}/>;
case 'photos':
return <Photos key={key} id={key} {...section.fields}/>;
case 'postGrid':
return <PostGrid key={key} id={key} {...section.fields}/>;
case 'splitView':
return <SplitView key={key} id={key} {...section.fields}/>;
case 'text':
return <Text key={key} id={key} {...section.fields}/>;
case 'tile':
return <Tile key={key} id={key} {...section.fields}/>;
default:
return null;
}
The problem with this is that Gatsby will include all available components in the webpack chunk which leads to a blown up site if there are many of them. Let's say there is a page with text only (e.g. imprint) the YouTube player and photos component would be loaded too - just not used.
So... is there a way to render components based on data which then results in proper code-splitting?
Thank you so much!
Upvotes: 2
Views: 1640
Reputation: 347
React Loadable has worked brilliantly for me. This is one of those cases when adding a library makes the bundle smaller.
You might also want to defer async loading to when the user has scrolled to the particular element, which this library doesn't do by itself. You can easily mix the original with the InteractionObserver version - react-loadable-visibility. However, make sure you have a good way of handling CLS (Cumulative Layout Shift) or Lighthouse will complain that your website elements are frustrating your users.
Upvotes: 1
Reputation: 29320
I'm thinking of another approach; in a mapping component that renders your type of component based on contentType
, much more cleaner and especially, a huge performance improvement (no need to force the code to check for the switch
statement each time).
Without seeing the rest of the code it's difficult to guess how you are printing that switch
. However, let's say you have all your data inside data
object, then:
import SwitchComponents from '../../SwitchComponents/SwitchComponents'
// other code
return data.map(item => {
const Switcher = SwitchComponents[item.contentType];
return (
<Switcher
key={item.key} // or something unique
{...section.fields}
/>
);
})
This component should have a similar structure, such as:
import Billboard from './Billboard/Billboard';
import Photos from './Photos/Photos';
import PostGrid from './PostGrid/PostGrid';
import SplitView from './SplitView /SplitView';
import Text from './Text/Text';
import Tile from './Tile/Tile';
const SwitchComponents= {
billboard : Billboard,
photos : Photos,
postGrid : PostGrid,
splitView : SplitView,
text : Text,
tile : Tile
};
export default SwitchComponents
Basically you are telling with SwitchComponents[item.contentType]
the position of SwitchComponents
that should take, since it's mapped as a component (imported in SwitchComponents
) and rendered as <Switcher/>
will get a component and will do the trick.
I would be glad to upload the question if it breaks but I hope you get my workaround.
Let me know how it works!
Upvotes: 1