I have implemented an editor with tinymce package and I have the comments plug in. In addition I have built a functionality as follows: When a user select a text, I store it on a state variable in order to read it from the tiny's built in create function and send all the data to my backend. Overall I want when a user select a text in order to create a comment, to send the highlighted text to my backend through the tiny's create function but the create function only reads the initial state of the variable and does not read the updated value. The code id as below:
import { Editor as EditorMce } from "@tinymce/tinymce-react";
//... some imports
function Editor() {
let [highlightedText, setHighlightedText] = useState("");
const tinycomments_create = (req, done, fail) => {
const { content, createdAt } = req;
console.log("highligt inside create function");
console.log(highlightedText); //This is always an empy string, the initial value
//and does not update when user highlights a text
fetch("my-backend-endpoint", {
method: "POST",
body: JSON.stringify({
content,
createdAt,
highlightedText,
}),
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
})
.then((response) => {
if (!response.ok) {
throw new Error("Failed to create comment");
}
return response.json();
})
.then((req2) => {
const conversationUid = req2.id;
done({ conversationUid });
})
.catch((e) => {
fail(e);
});
};
//... some existing code and I return the component
<EditorMce
value={session ? session.sessionText : ""}
onEditorChange={handleOnEditorChange}
init={{
init_instance_callback: (editor) => {
editor.on("MouseUp", function (e) {
if (e.view.getSelection().toString() !== "") {
setHighlightedText(e.view.getSelection().toString());
}
});
},
content_css: "writer",
height: "80%",
width: "95%",
plugins: [
"tinycomments",
"advlist",
"autolink",
"lists",
"link",
"image",
"charmap",
"preview",
"anchor",
"searchreplace",
"visualblocks",
"code",
"fullscreen",
"insertdatetime",
"media",
"table",
"code",
"help",
"wordcount",
],
menubar: "file edit view insert format tools tc",
menu: {
tc: {
title: "Comments",
items: "addcomment showcomments deleteallconversations",
},
},
toolbar:
"undo redo | fontsizeinput fontfamily | blocks | " +
"bold italic forecolor backcolor | alignleft aligncenter " +
"alignright alignjustify | bullist numlist outdent indent | " +
"removeformat | addcomment showcomments | help",
content_style:
"body { font-family:Helvetica,Arial,sans-serif; font-size:16px }" +
".tox-comments-visible span.tox-comment { background-color: #90EE90!important; }.tox-comments-visible span.tox-comment--active { background-color: black; }",
tinycomments_create,
tinycomments_reply,
tinycomments_edit_comment,
tinycomments_delete,
tinycomments_delete_all,
tinycomments_delete_comment,
tinycomments_lookup,
}}
/>
}
How can I update the value of highlightedText inside tinycomments_create. I have tried the useCallback hook with no result. Also I have tried to add the tinycomments_create inside a useEffect and set it every time the highlightedText updates but again with no results. Any thoughts on that?
Instead of using useState
, you can use a useRef
:
// replace
const [highlightedText, setHighlightedText] = useState("");
// by
const highlightedText = useRef("");
Then when updating this value
// replace
setHighlightedText(e.view.getSelection().toString());
// by
highlightedText.current = e.view.getSelection().toString();
Finally, inside the tinycomments_create
function, you can read the most up-to-date value from highlightedText.current
.
Note that updating a ref won't cause a render, thus the UI won't get updated. If you want the UI to update, you would have to use a useState
along with the proposed useRef
approach.
TLDR: using useRef
is essential for the tinycomments_create
to read the last value of highlightedText
; while using useState
is essential if you want to make a render and update the UI.