How to save and load editor state from localStorage with React? #1937
-
From the examples: const initialEditorState = await loadContent();
const editorStateRef = useRef();
<LexicalComposer ...>
<LexicalRichTextPlugin initialEditorState={initialEditorState} />
<LexicalOnChangePlugin onChange={editorState => editorStateRef.current = editorState} />
<Button label="Save" onPress={() => {
if (editorStateRef.current) {
saveContent(editorStateRef.current.toJSON())
}
}} />
</LexicalComposer> This makes sense, except for how I'd like to pass I would've expected What's the best way to solve this problem at the moment? Thanks 🙏 |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 11 replies
-
It's not obvious but
Does passing the JSON.stringifed version work for you? |
Beta Was this translation helpful? Give feedback.
-
This is what I ended up going with. I'd love for it to work on first render, though I couldn't seem to get that working. import { useLocalStorage } from 'react-use'
import OnChangePlugin from '@lexical/react/LexicalOnChangePlugin'
function RestoreFromLocalStoragePlugin() {
const [editor] = useLexicalComposerContext()
const [serializedEditorState, setSerializedEditorState] = useLocalStorage<
string | null
>('my-editor-state-example-key', null)
const [isFirstRender, setIsFirstRender] = React.useState(true)
React.useEffect(() => {
if (isFirstRender) {
setIsFirstRender(false)
if (serializedEditorState) {
const initialEditorState = editor.parseEditorState(serializedEditorState)
editor.setEditorState(initialEditorState)
}
}
}, [isFirstRender, serializedEditorState, editor])
const onChange = React.useCallback(
(editorState: EditorState) => {
setSerializedEditorState(JSON.stringify(editorState.toJSON()))
},
[setSerializedEditorState]
)
// TODO: add ignoreSelectionChange
return <OnChangePlugin onChange={onChange} />
} |
Beta Was this translation helpful? Give feedback.
-
easier if just make another plugins I think the concept similar like make readOnly
attach onChange with handlers
|
Beta Was this translation helpful? Give feedback.
-
The const loadContent = async () => {
// read from database, local storage, etc.
// 'empty' editor
const value = '{"root":{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"root","version":1}}';
return value;
}
const initialEditorState = await loadContent();
const initialConfig = {
namespace: 'Editor',
theme: {},
onError: (error) => console.log(error),
editorState: initialEditorState,
};
<LexicalComposer initialConfig={initialConfig}>
<LexicalRichTextPlugin
contentEditable={<LexicalContentEditable />}
placeholder=""
/>
<LexicalOnChangePlugin
onChange={editorState => {
editorState.read(() => {
// write to database, local storage, etc.
const value = JSON.stringify(editorState); // or JSON.stringify(editorState.toJSON())
console.log(value);
});
}}
/>
</LexicalComposer> |
Beta Was this translation helpful? Give feedback.
-
If you need to avoid the onChange handler of being triggered initially this is possible by explicitly setting the Using const editorConfig = {
namespace: 'my-editor',
theme: DefaultTheme,
onError(error: Error) {
throw error;
},
editorState: null, <---
nodes: [
HeadingNode,
ImageNode,
ListNode,
ListItemNode,
QuoteNode,
CodeNode,
CodeHighlightNode,
TableNode,
TableCellNode,
TableRowNode,
AutoLinkNode,
LinkNode,
HorizontalRuleNode
]
};
...
<LexicalComposer initialConfig={editorConfig}>
...
</LexicalComposer> |
Beta Was this translation helpful? Give feedback.
-
didn't read. this worked for me in Next.js function LocalStoragePlugin() {
const [editor] = useLexicalComposerContext()
useEffect(() => {
const state = editor.parseEditorState(
localStorage?.editor || editor.getEditorState()
)
editor.setEditorState(state)
}, [editor])
return null
} |
Beta Was this translation helpful? Give feedback.
-
In React using TypeScript, getting the Variable declaration -> Then I was able to pass it into the config object like so. const initialConfig = {
namespace: 'EditorWidget',
theme,
onError,
nodes: [
HeadingNode
],
editorState: initialEditorState,
}; |
Beta Was this translation helpful? Give feedback.
This is what I ended up going with. I'd love for it to work on first render, though I couldn't seem to get that working.