`serializeHtml` throws `Invalid hook call` error
Description
When calling serializeHtml (from @udecode/plate-serializer-html), React throws an invalid hook error:
Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
Steps to Reproduce
I have a component, CustomPlateEditor. In this component, I have:
<DndProvider backend={HTML5Backend}>
<Plate editorRef={editorRef} initialValue={initialValue ?? defaultInitialValue} onChange={onChange} plugins={PLATE_PLUGINS}>
<FixedToolbar>
<FixedToolbarButtons/>
</FixedToolbar>
<Editor focusRing={false} id='PlateEditor' />
<FloatingToolbar>
<FloatingToolbarButtons/>
</FloatingToolbar>
</Plate>
</DndProvider>
My editorRef is passed down from a parent component, which contains the following code:
export const SomeOtherComponent = () => {
const editorRef = useRef<PlateEditor | null>(null);
const [editorValue, setEditorValue] = useState<TElement[]>(defaultInitialValue);
const [editorHtmlValue, setEditorHtmlValue] = useState('');
const onEditorChange = (value: TElement[]) => {
setEditorValue(value);
if (!editorRef.current) return;
const html = serializeHtml(editorRef.current, {
nodes: editorRef.current.children,
dndWrapper: (props) => <DndProvider backend={HTML5Backend} {...props} />
});
setEditorHtmlValue(html);
};
// Other logic here
return <>
{/* Other stuff here */}
<CustomPlateEditor editorRef={editorRef} initialValue={editorValue} onChange={onEditorChange} />
</>
}
When making any sort of change inside my Plate editor, I end up getting the invalid hook error, which I've narrowed down to only happening due to the nodes: editorRef.current.children part of the serializeHtml function. I've tried various other approaches including creating a temporary editor and passing in the editor value, but I get the same React hook error. I've checked that I don't have different versions of React running, so it seems to be an issue within @udecode/plate-serializer-html
Sandbox
I will make a code sandbox within a couple of days and update this issue.
Expected Behavior
I would expect that, with the given code I have in my app, making any change to the Plate rich text editor would result in a raw html string being set for my editorHtmlValue state value.
Environment
- slate:
[email protected] - slate-react:
[email protected] - browser: chrome
- PlateJS:
@udecode/[email protected]
Funding
- You can sponsor this specific effort via a Polar.sh pledge below
- We receive the pledge once the issue is completed & verified
Is there any update?
Same error. Here is the screenshot.
No ETA until consulting request.
I'm having the same issue.
Having the issue too
@zbeyens Any solution?
After thorough debugging over several hours, it was determined that the issue arose from the inclusion of the createBlockSelectionPlugin with specific options, notably:
createBlockSelectionPlugin({ options: { sizes: { top: 0, bottom: 0, }, }, })
The solution involved filtering the array of plugins to exclude the blockSelection plugin:
const excludedSelectionPlugin = plugins?.filter(plugin => plugin?.key !== 'blockSelection');
Subsequently, the modified array excludedSelectionPlugin was passed to the createPlateEditor function:
serializeHtml(createPlateEditor({ plugins: excludedSelectionPlugin }), { nodes: textEditor, data, dndWrapper: props => <DndProvider backend={HTML5Backend} {...props} />, })
This adjustment successfully resolved the encountered issue.
Hope you will figure out the original issue which was caused by 'createBlockSelectionPlugin';
@andshonia Thank you. Your solution works in my case.
I have the same issue but the workaround is not working for me. It appears that other plugins might also have bug which is causing invalid hook call. Issue happens inside the serializeHtml() call.
Here have the error message call serializeHtml function. how can I do to resolve this error?
Invalid hook call. Hooks can only be called inside of the body of a function component.
After thorough debugging over several hours, it was determined that the issue arose from the inclusion of the createBlockSelectionPlugin with specific options, notably:
createBlockSelectionPlugin({ options: { sizes: { top: 0, bottom: 0, }, }, })The solution involved filtering the array of plugins to exclude the blockSelection plugin:
const excludedSelectionPlugin = plugins?.filter(plugin => plugin?.key !== 'blockSelection');Subsequently, the modified array excludedSelectionPlugin was passed to the createPlateEditor function:
serializeHtml(createPlateEditor({ plugins: excludedSelectionPlugin }), { nodes: textEditor, data, dndWrapper: props => <DndProvider backend={HTML5Backend} {...props} />, })This adjustment successfully resolved the encountered issue.
Hope you will figure out the original issue which was caused by 'createBlockSelectionPlugin';
I find out, that your solution is not working for me, and made some debugging. now I can See, that createTogglePlugin also causes this bug.
I was also facing the same issue:
Workaround (that worked for me):
createPlateEditor({ plugins: plugins?.filter( (plugin) => plugin?.key !== 'toggle' && plugin?.key !== 'blockSelection' ), })
By filter out the toggle and blockSelection, the html serialization is now working for me. Furthermore, I do suggest adding context={window} on DndWrapper according to this comment: Multiple DndProviders inside a pure component can lead to Cannot have two HTML5 backends at the same time #3257, if anyone faces cannot have two HTML5Backend problem from DnDWrapper.
for me filtering toggle and blockSelection did not work. i needed to filter p also
const filteredPlugins = plugins?.filter((plugin) => plugin?.key !== 'toggle' && plugin?.key !== 'blockSelection' && plugin?.key !== 'p');
Latest v34
for me filtering
toggleandblockSelectiondid not work. i needed to filterpalso
const filteredPlugins = plugins?.filter((plugin) => plugin?.key !== 'toggle' && plugin?.key !== 'blockSelection' && plugin?.key !== 'p');Latest v34
I removed the p filtering now it works without it!!!!
But i am facing another problem, i am desearilizing a html and showing it in the editor, but if there is any text, (p tag), the editor get reset if i type something