What I have:
- I have a UI-kit written as React library and tailwind.
- Each element in this UI-kit uses a functional approach and hooks.
- Every component has logic that depends on props (which I convert to attributes).
and the problem is that I cannot reuse these components inside the save function of Gutenberg due to the constraints of this function. (save function can't use components/function that has side effects like hooks)
so, in the first case where I've needed to just re-use my component I used this approach:
export default function save({attributes}) {
const {text , variant} = attributes;
return (
<>
{parseHTML(ReactDOMServer.renderToString(
<Button variant={variant}>
<RichText.Content value={text}/>
</Button>
))}
</>
);
}
- Convert component and its subcomponents to string using react-dom/server
- Convert that string into a single react component using html-react-parser
- Provide this component to save function
And it worked perfectly so far I didn't need to use InnerBlocks for nested blocks:
const save = ({attributes}) => {
return (
<div>
{parseHTML(
ReactDOMServer.renderToString(
<Wrapper>
<InnerBlocks.Content/>
</Wrapper>
)
)}
</div>
);
}
and the error:
index.js:5130 Uncaught (in promise) Error: Component(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
at validateRenderResult (index.js:5130)
at processChild (index.js:5254)
at resolve (index.js:5150)
at ReactDOMServerRenderer.render (index.js:5633)
at ReactDOMServerRenderer.read (index.js:5570)
at Object.renderToString (index.js:6178)
at save (index.js:7448)
at getSaveElement (blocks.js:9166)
at getSaveContent (blocks.js:9213)
at addParsedDifference (block-editor.js:14707)
UPD: example of component from UI library
import React , {useMemo} from "react";
import clsx from "clsx";
const DefaultButton = ({className, rounded, ...props}) => {
const classes = useMemo(() => clsx([
className,
"shroud-px-6 shroud-py-3",
"shroud-font-bold shroud-text-white",
"shroud-bg-white shroud-bg-secondary-100 hover:shroud-bg-primary-100",{
"shroud-rounded-full": rounded,
}
]) , [className]);
return <button className={classes} {...props} />
};
export default DefaultButton;