Last active
July 22, 2021 13:17
-
-
Save jbreuer/b63cd87a9b15ff1f660cb8847413d1d8 to your computer and use it in GitHub Desktop.
Hybrid Placeholder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useEffect, useState } from 'react'; | |
import { withSitecoreContext, dataApi, Placeholder } from '@sitecore-jss/sitecore-jss-react'; | |
import { dataFetcher } from './dataFetcher'; | |
import config from './temp/config'; | |
const HybridPlaceholder = ({ | |
name, | |
rendering, | |
sitecoreContext, | |
}) => { | |
const { | |
route, | |
pageEditing, | |
} = sitecoreContext; | |
const [isFetched, setIsFetched] = useState(false); | |
// Used to fetch the placeholder data with specific parameters. | |
const fetchPlaceholder = () => dataApi.fetchPlaceholderData( | |
name, | |
route?.itemId, | |
{ | |
layoutServiceConfig: { | |
host: config.sitecoreApiHost, | |
}, | |
querystringParams: { | |
sc_lang: route?.itemLanguage, | |
sc_apikey: config.sitecoreApiKey, | |
isHybridPlaceholder: true, | |
}, | |
fetcher: dataFetcher, | |
}, | |
); | |
// Will add the isLoaded prop to all components. | |
const addIsLoadedProp = (isLoaded, elements) => { | |
if (Array.isArray(elements)) { | |
elements.forEach(({ fields }) => { | |
if (fields) { | |
fields.isLoaded = isLoaded; | |
} | |
}); | |
} | |
}; | |
// Only fetch the placeholder data when we navigate to a new page. | |
// Since useEffect does not work server-side we don't need a client-side check. | |
useEffect(() => { | |
if (!pageEditing && rendering?.placeholders?.[name]) { | |
setIsFetched(false); | |
fetchPlaceholder() | |
.then(result => { | |
addIsLoadedProp(true, result.elements); | |
// Override all components in the placeholder with the new data. | |
// This data contains the heavy code. | |
rendering.placeholders[name] = result.elements; | |
setIsFetched(true); | |
}).catch(error => { | |
console.error(error); | |
}); | |
} | |
}, [route?.itemId]); | |
if (!pageEditing | |
&& !isFetched | |
&& rendering?.placeholders?.[name]) { | |
addIsLoadedProp(false, rendering.placeholders[name]); | |
} | |
return ( | |
// Render the first time without the heavy data. | |
// Render a second time with all the data loaded. | |
<Placeholder name={name} rendering={rendering} /> | |
); | |
}; | |
export default withSitecoreContext()(HybridPlaceholder); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const PromoBlock = (props) => { | |
const { | |
image, | |
richText, | |
heading, | |
button, | |
isLoaded | |
} = props; | |
return ( | |
<Theme> | |
<Layer> | |
<Retain> | |
{ isLoaded && ( | |
<p>Date: {props.date}</p> | |
)} | |
{ !isLoaded && ( | |
<p>Date: Loading...</p> | |
)} | |
<div className="c-promoblock"> | |
<div className="o-layout o-layout--gutter"> | |
<div className="o-layout__cell u-fraction--1/2@from-lap"> | |
<Img image={image} className="u-m-b" /> | |
</div> | |
<div className="o-layout__cell u-fraction--1/2@from-lap"> | |
<Heading text={heading.text} level={heading.level} className="u-m-t-tiny" /> | |
<Rte richText={richText} /> | |
{button ? ( | |
<Button tag="button" modifier="secondary" field={button} /> | |
) : null} | |
</div> | |
</div> | |
</div> | |
</Retain> | |
</Layer> | |
</Theme> | |
); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class PromoRenderingContentsResolver : IRenderingContentsResolver | |
{ | |
private readonly Func<IMvcContext> contextThunk; | |
private readonly IMapper mapper; | |
public PromoRenderingContentsResolver(Func<IMvcContext> contextThunk, IMapper mapper) | |
{ | |
this.contextThunk = contextThunk; | |
this.mapper = mapper; | |
} | |
public override object ResolveContents(Rendering rendering, IRenderingConfiguration renderingConfig) | |
{ | |
var context = this.contextThunk(); | |
var datasource = context.GetDataSourceItem<Promo>(); | |
var model = this.mapper.Map<PromoJsonDto>(datasource); | |
if (this.IsHybridPlaceholder) | |
{ | |
// Here the heavy code can be executed which will be done async. | |
// So after the page is already loaded this will be added afterwards. | |
Thread.Sleep(2000); | |
model.Date = DateTime.Now.ToString("f"); | |
} | |
return model; | |
} | |
private bool IsHybridPlaceholder | |
{ | |
get | |
{ | |
bool.TryParse(HttpContext.Current?.Request?.QueryString?["isHybridPlaceholder"], out var isHybridPlaceholder); | |
return isHybridPlaceholder; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment