How to easily set entire SlateJS editor value using React onEffect hook?
The initial editor value is set when creating the useState hook, however, I want to set a new initial value afterwards.
Currently, we can do that by deleting all elements with Transform and then inserting new elements, but is an easier way, like override all? I can't seem to find it in the SlateJS docs.
Saving to database slatejs example Don't work, but is how my setup functions
const App = () => {
const editor = useMemo(() => withReact(createEditor()), [])
// Update the initial content to be pulled from Local Storage if it exists.
const [value, setValue] = useState(
[
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
]
)
useEffect(() => {
// Get saved SlateJS text from local storage
const savedSlateTextData = getSavedSlateJSData(localStorage)
// In theory, this should set the SlateJS values to the loaded data
// In practice, I think because the editor is immutable outside transform, it don't work
setValue(savedSlateTextData)
}, [])
return (
<Slate
editor={editor}
value={value}
onChange={value => {
setValue(value)
const isAstChange = editor.operations.some(
op => 'set_selection' !== op.type
)
if (isAstChange) {
// Save the value to Local Storage.
const content = JSON.stringify(value)
localStorage.setItem('content', content)
}
}}
>
<Editable />
</Slate>
)
}
Don't think what I want is possible — you need to delete all the nodes and then insert new ones.
Not sure if you could use match instead of a bunch of for loops, perhaps.
// Get initial total nodes to prevent deleting affecting the loop
let totalNodes = editor.children.length;
// No saved content, don't delete anything to prevent errors
if (savedSlateJSContent.length <= 0) return;
// Remove every node except the last one
// Otherwise SlateJS will return error as there's no content
for (let i = 0; i < totalNodes - 1; i++) {
console.log(i)
Transforms.removeNodes(editor, {
at: [totalNodes-i-1],
});
}
// Add content to SlateJS
for (const value of savedSlateJSContent ) {
Transforms.insertNodes(editor, value, {
at: [editor.children.length],
});
}
// Remove the last node that was leftover from before
Transforms.removeNodes(editor, {
at: [0],
});
This is the cleanest way I could think of using what's available via slate
const INITIAL_SLATE_VALUE = [
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
]
const [value, setValue] = useState(INITIAL_SLATE_VALUE)
// Delete all entries leaving 1 empty node
Transforms.delete(editor, {
at: {
anchor: Editor.start(editor, []),
focus: Editor.end(editor, []),
},
})
// Removes empty node
Transforms.removeNodes(editor, {
at: [0],
})
// Insert array of children nodes
Transforms.insertNodes(
editor,
value
)