0

I'm using sitecore JSS, I have a component with a placeholder and I am trying to add a child component into that placeholder. I'm getting an unhelpful popup error saying An error occurred and then in the console I get the slightly more descriptive, but also largely unhelpful error Could not find the rendering in the HTML loaded from server.

I've been able to narrow down the problem to what the component renders as a default on SSR:

import React from "react";
import { withPlaceholder, isExperienceEditorActive } from "@sitecore-jss/sitecore-jss-react";
import { DeviceWidth } from "../Utils/device";
import { CardList, MobileCardList, CardListSkeleton } from "componentlib";


const JSSCardCarousel = ({ fields, cardCarouselPlaceholder }) => {
  if (isExperienceEditorActive()) {
    return <div>{cardCarouselPlaceholder}</div>;
  }
  return width === DeviceWidth.Unknown ? (
    // Note the Skeleton, default state doesn't render the placeholder on purpose
    <CardListSkeleton />
  ) : (
    <CardList>{cardCarouselPlaceholder}</CardList>
    <MobileCardList>{cardCarouselPlaceholder</CardList>
  );
};

export default withPlaceholder({
  placeholder: "card-carousel-placeholder",
  prop: "cardCarouselPlaceholder"
})(JSSCardCarousel); 

I have a trimmed down section component that holds cards. If i know it's EE, i return the cards placeholder in a div. Otherwise if I don't know the device width (i.e., I'm SSR) , I render a skeleton state and then when I get to the client, we render a card list and mobile card list (they use breakpoints to determine which to show. The problem is with the CardListSkeleton. In EE, that is the default case for this component. This works fine in normal rendering of the page, but in EE, a component that does not render it's placeholder as it's default case throws the error I mentioned earlier: Could not find the rendering in the HTML loaded from server.

This seems like a legitimate bug in the experience editor.

We have this issue with multiple components (e.g., a modal component that only renders the placeholder contents into the dom when the modal opens). If there was a way to ensure isExperienceEditorActive() on SSR, I think this would be a lot better. My workaround right now is to always render the placeholder in a <span hidden>{myplaceholder}</span> by default alongside the actual default. Pretty irritating that I have to encode my placeholder contents twice on the page in order to appease one small facet of the EE.

Any other help greatly appreciated!!

1 Answer 1

0

This behavior seems unexpected and feels like a legitimate bug in how the Experience Editor (EE) is handling jss renderings (i.e., the fact that if a rendering doesn't by default render the placeholder server-side, it doesn't blow up when trying to add to that rendering's placeholder in EE).

Here's the best workaround to this problem that I've now gone with:

Use sitecoreContext && sitecoreContext.pageEditing via the withSitecoreContext HOC instead of isExperienceEditorActive to ensure that, in the EE, the component is always rendered client and server side with its placeholder. Apparently isExperienceEditorActive works exclusively on client side and will never return true if rendering on the server, even if in the experience editor. So my updated component would look something like:

import React from "react";
import { withPlaceholder, withSitecoreContext } from "@sitecore-jss/sitecore-jss-react";
import { DeviceWidth } from "../Utils/device";
import { CardList, MobileCardList, CardListSkeleton } from "componentlib";
import compose from "ramda/src/compose"; // Or use from redux, recompose, lodash, roll your own, etc...

const JSSCardCarousel = ({ fields, cardCarouselPlaceholder, sitecoreContext }) => {
  const isEditing = sitecoreContext && sitecoreContext.pageEditing;

  if (isEditing) {
    return <div>{cardCarouselPlaceholder}</div>;
  }
  return width === DeviceWidth.Unknown ? (
    // Note the Skeleton, default state doesn't render the placeholder on purpose
    <CardListSkeleton />
  ) : (
    <CardList>{cardCarouselPlaceholder}</CardList>
    <MobileCardList>{cardCarouselPlaceholder</CardList>
  );
};

const withComposedHOCs = compose(
  withSitecoreContext(),
  withPlaceholder({
    placeholder: "card-carousel-placeholder",
    prop: "cardCarouselPlaceholder"
  })
);

export default withComposedHOCs(JSSCardCarousel); 

Hopefully Sitecore can address this bug, but in the meantime I hope this workaround helps other folks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.