-
-
Save sebastiantecsi/7a8f5ca997d71cc278c31ee32cf36548 to your computer and use it in GitHub Desktop.
Hybrid Placeholder
This file contains 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 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 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