Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand react docs #4845

Merged
merged 1 commit into from
Jul 31, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 92 additions & 13 deletions packages/lexical-website/docs/getting-started/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,6 @@ const theme = {
...
}

// When the editor changes, you can get notified via the
// LexicalOnChangePlugin!
function onChange(editorState) {
editorState.read(() => {
// Read the contents of the EditorState here.
const root = $getRoot();
const selection = $getSelection();

console.log(root, selection);
});
}

// Lexical React plugins are React components, which makes them
// highly composable. Furthermore, you can lazy load plugins if
// desired, so you don't pay the cost for plugins until you
Expand Down Expand Up @@ -91,10 +79,101 @@ function Editor() {
placeholder={<div>Enter some text...</div>}
ErrorBoundary={LexicalErrorBoundary}
/>
<OnChangePlugin onChange={onChange} />
<HistoryPlugin />
<MyCustomAutoFocusPlugin />
</LexicalComposer>
);
}
```

Now that we have a simple editor in React, the next thing we might want to do is access the content of the editor to, for instance,
save it in a database. We can do this via the an [update listener](https://lexical.dev/docs/concepts/listeners#registerupdatelistener), which will execute every time the editor state changes and provide us with the latest state. In React, we typically use the plugin system to set up listeners like this, since it provides us easy access to the LexicalEditor instance via a React Context. So, let's write our own plugin that notifies us when the editor updates.

```jsx
// When the editor changes, you can get notified via the
// OnChangePlugin!
function OnChangePlugin({ onChange }) {
// Access the editor through the LexicalComposerContext
const [editor] = useLexicalComposerContext();
// Wrap our listener in useEffect to handle the teardown and avoid stale references.
useEffect(() => {
// most listeners return a teardown function that can be called to clean them up.
return editor.registerUpdateListener((editorState) => {
// call onChange here to pass the latest state up to the parent.
onChange(editorState);
});
}, [editor, onChange]);

}
```

Now, we can implement this in our editor and save the EditorState in a React state variable:

```jsx
function OnChangePlugin({ onChange }) {
const [editor] = useLexicalComposerContext();
useEffect(() => {
return editor.registerUpdateListener((editorState) => {
onChange(editorState);
});
}, [editor, onChange]);
}

function Editor() {
// ...

const [editorState, setEditorState] = useState();
function onChange(editorState) {
setEditorState(editorState);
}

return (
<LexicalComposer initialConfig={initialConfig}>
<PlainTextPlugin
contentEditable={<ContentEditable />}
placeholder={<div>Enter some text...</div>}
ErrorBoundary={LexicalErrorBoundary}
/>
<HistoryPlugin />
<MyCustomAutoFocusPlugin />
<OnChangePlugin onChange={onChange}/>
</LexicalComposer>
);
}

```
Ok, so now we're saving the EditorState object in a React state variable, but we can't save a JavaScript object to our database - so how do we persist the state so we can load it later? We need to serialize it to a storage format. For this purpose (among others) Lexical provides several serialization APIs that convert EditorState to a string that can be sent over the network and saved to a database. Building on our previous example, we can do that this way:

```jsx
function OnChangePlugin({ onChange }) {
const [editor] = useLexicalComposerContext();
useEffect(() => {
return editor.registerUpdateListener((editorState) => {
onChange(editorState);
});
}, [editor, onChange]);
}

function Editor() {
// ...

const [editorState, setEditorState] = useState();
function onChange(editorState) {
// Call toJSON on the EditorState object, which produces a serialization safe string
const editorStateJSON = editorState.toJSON();
// However, we still have a JavaScript object, so we need to convert it to an actual string with JSON.stringify
setEditorState(JSON.stringify(editorStateJSON));
}

return (
<LexicalComposer initialConfig={initialConfig}>
{/*...*/}
<OnChangePlugin onChange={onChange}/>
</LexicalComposer>
);

```

From there, it's straightforward to wire up a submit button or some other UI trigger that will take the state from the React state variable and send it to a server for storage in a database.

One important thing to note: Lexical is generally meant to be uncontrolled, so avoid trying to pass the EditorState back into Editor.setEditorState or something along those lines.