Skip to content

Commit

Permalink
fix: automatically assign keys to custom <PrismicRichText> componen…
Browse files Browse the repository at this point in the history
…ts (#118)

* fix: automatically assign keys to custom `<PrismicRichText>` components

* refactor: only call `React.cloneElement` if necessary
  • Loading branch information
angeloashmore authored Jan 26, 2022
1 parent a7a34d0 commit 9e609f6
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 7 deletions.
27 changes: 20 additions & 7 deletions src/PrismicRichText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,6 @@ export const PrismicRichText = (
return null;
} else {
const linkResolver = props.linkResolver || context.linkResolver;
const defaultSerializer = createDefaultSerializer({
linkResolver,
internalLinkComponent: props.internalLinkComponent,
externalLinkComponent: props.externalLinkComponent,
});

const serializer = prismicR.composeSerializers(
typeof props.components === "object"
Expand All @@ -237,10 +232,28 @@ export const PrismicRichText = (
typeof context.richTextComponents === "object"
? prismicR.wrapMapSerializer(context.richTextComponents)
: context.richTextComponents,
defaultSerializer,
createDefaultSerializer({
linkResolver,
internalLinkComponent: props.internalLinkComponent,
externalLinkComponent: props.externalLinkComponent,
}),
);

const serialized = prismicR.serialize(props.field, serializer);
// The serializer is wrapped in a higher-order function
// that automatically applies a key to React Elements
// if one is not already given.
const serialized = prismicR.serialize<JSX.Element>(
props.field,
(type, node, text, children, key) => {
const result = serializer(type, node, text, children, key);

if (React.isValidElement(result) && result.key == null) {
return React.cloneElement(result, { key });
} else {
return result;
}
},
);

return <>{serialized}</>;
}
Expand Down
37 changes: 37 additions & 0 deletions test/PrismicRichText.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import test from "ava";
import * as prismicT from "@prismicio/types";
import * as React from "react";
import * as sinon from "sinon";

import { renderJSON } from "./__testutils__/renderJSON";

Expand Down Expand Up @@ -583,3 +584,39 @@ test("components given to components prop overrides components given to PrismicP

t.deepEqual(actual, expected);
});

// This test spies on `console.error()`. As a result, it must be run serially
// to avoid affecting other tests.
test.serial("keys are automatically applied to custom components", (t) => {
const field: prismicT.RichTextField = [
{
type: prismicT.RichTextNodeType.heading1,
text: "heading1",
spans: [],
},
{
type: prismicT.RichTextNodeType.paragraph,
text: "paragraph",
spans: [],
},
];

const consoleErrorSpy = sinon.stub(console, "error");
consoleErrorSpy.callsFake(() => {
// no-op
});

renderJSON(
<PrismicRichText
field={field}
components={{
heading1: ({ children }) => <h1>{children}</h1>,
paragraph: ({ children }) => <p>{children}</p>,
}}
/>,
);

t.false(consoleErrorSpy.calledWith(sinon.match(/unique "key"/)));

consoleErrorSpy.restore();
});

0 comments on commit 9e609f6

Please sign in to comment.