I'm trying to populate a rich text editor (tiptap.dev) with the response from an API call. After calling the setEditorContent hook with the data payload, the editor content should update. I notice that when I modify the local file and save it, the API data is rendered in the DOM (but not on the initial page load).
export default function EditHandbook() {
const router = useRouter();
const user = useUser();
const { query } = useRouter();
const [loading, setLoading] = useState(true);
const [editorContent, setEditorContent] = useState(null);
// Get handbook by ID
const id = query.id;
let handbookText = null;
function loadDataOnlyOnce() {
axios
.get("/api/templater/" id "/")
.then((res) => {
handbookText = res.data.handbookContent; // the object returned from api/templater/[id].js
})
.finally(() => {
setEditorContent(handbookText);
setLoading(false);
})
.catch((err) => console.log(err));
}
useEffect(() => {
loadDataOnlyOnce();
}, [id]); // only run once, after id is resolved from router on page load
const editor = useEditor({
extensions: [StarterKit],
onUpdate({ editor }) {
setEditorContent(editor.getHTML());
},
content: editorContent,
});
return (
<div>
<TextEditorMenubar editor={editor} />
<EditorContent editor={editor} />
</div>
);
}
CodePudding user response:
You should wrap id in a useState. This worked for me
const router = useRouter();
const [id, setId] = useState(router.query.id);
useEffect(() => {
setId(router.query.id);
// Test if the id is not null
if (id) {
loadDataOnlyOnce();
}
}, [router, id]);
Also pass the router object to the useEffect so react knows to fire that function when the router changes.
CodePudding user response:
I think you should add:
if (loading) return "something is loading";
return (
<div>
<TextEditorMenubar editor={editor} />
<EditorContent editor={editor} />
</div>
);
and don't do a useEffect(() => setId(id), [id]) because you will rerendering forever. In case you need, do it be behind an if to control it
