onUpdate callback does not update after re-render
See original GitHub issueWhat’s the bug you are facing?
I have a wrapper around tiptap, whenever the text changes I trigger a request to my back-end, this works fine the first time tiptap is mounted but the parent component (where tiptap is mounted) can change its internal variables, and therefore the closure should capture a new context, the problem is that it doesn’t after the parent component changes the state, the closure/lambda passed on the onUpdate
function remains the same and therefore tiptap tries to update the wrong component.
Here is some of the code, my high level component on the parent, notice the id
param, which is the param that changes at some point:
<Tiptap
onFocus={({ editor }) => editor.commands.blur()}
initialContent={project.notes ? JSON.parse(project.notes) : null}
placeholder="You can add a default checklist in the settings."
className="md:max-w-2xl lg:max-w-none"
onChange={async (e) => {
console.warn("URL PARAM ID", id) // ALWAYS REMAINS THE SAME, THEREFORE CANNOT UPDATE THE PROJECT CORRECTLY
await updateProjectMutation({
id,
notes: JSON.stringify(e),
})
refetch()
}}
ref={tiptapRef}
/>
My internal TIptap implementation, notice the onUpdate
function that I’m passing to the useEditor
hook:
import Link from "@tiptap/extension-link"
import Placeholder from "@tiptap/extension-placeholder"
import TaskItem from "@tiptap/extension-task-item"
import TaskList from "@tiptap/extension-task-list"
import { BubbleMenu, EditorContent, Extension, useEditor } from "@tiptap/react"
import StarterKit from "@tiptap/starter-kit"
import React, { forwardRef, useImperativeHandle, useState } from "react"
import { useBoolean } from "../hooks/useBoolean"
import { Button } from "./Button"
interface IProps {
editable?: boolean
onClick?: (this: unknown, view: any, pos: number, event: MouseEvent) => boolean
initialContent?: any
// content?: any
onChange?: (content: any) => void
autofocus?: boolean | null | "end" | "start"
onFocus?: (params: { editor: any }) => void
placeholder?: string
className?: string
}
export const Tiptap = forwardRef<any, IProps>(
(
{
editable = true,
onClick,
initialContent,
onChange,
autofocus,
onFocus,
placeholder,
className,
// content,
},
ref
) => {
const [isAddingLink, addLinkOn, addLinkOff] = useBoolean()
const [link, setLink] = useState("")
const editor = useEditor({
autofocus,
onFocus: onFocus ? onFocus : () => {},
editorProps: {
attributes: {
class: "prose focus:outline-none dark:prose-dark dark:text-gray-300 text-base",
},
editable: () => editable,
handleClick: onClick,
},
content: initialContent,
onUpdate: ({ editor }) => {
onChange?.(editor.getJSON())
},
extensions: [
StarterKit,
Placeholder.configure({
showOnlyWhenEditable: false,
placeholder,
}),
TaskList.configure({
HTMLAttributes: {
class: "pl-0",
},
}),
TaskItem.configure({
HTMLAttributes: {
class: "before:hidden pl-0 flex items-center dumb-prose-remove",
},
}),
Extension.create({
// Do not insert line break when pressing CMD+Enter
// Most of the time handled by upper components
addKeyboardShortcuts() {
return {
"Cmd-Enter"() {
return true
},
"Ctrl-Enter"() {
return true
},
}
},
}),
Link,
],
})
useImperativeHandle(ref, () => ({
getEditorInstance() {
return editor
},
}))
return (
<EditorContent editor={editor} className={className} />
)
}
)
In any case, it seems the useEditor hook saves only the first passed onUpdate
function and does not update it in sub-sequent renders
How can we reproduce the bug on our side?
Attached the code above, but if necessary I can try to reproduce the issue in a code sandbox
Can you provide a CodeSandbox?
No response
What did you expect to happen?
The passed callback onUpdate
should be updated when a new value is passed to it, instead of constantly re-using the first memoized value
Anything to add? (optional)
I tried to update tiptap to the latest version but then I faced this other crash: https://github.com/ueberdosis/tiptap/issues/577 so I reverted to my old/current versions
"@tiptap/extension-bubble-menu": "2.0.0-beta.51",
"@tiptap/extension-link": "2.0.0-beta.33",
"@tiptap/extension-placeholder": "2.0.0-beta.45",
"@tiptap/extension-task-item": "2.0.0-beta.30",
"@tiptap/extension-task-list": "2.0.0-beta.24",
"@tiptap/react": "2.0.0-beta.98",
"@tiptap/starter-kit": "2.0.0-beta.154",
Did you update your dependencies?
- Yes, I’ve updated my dependencies to use the latest version of all packages.
Are you sponsoring us?
- Yes, I’m a sponsor. 💖
Issue Analytics
- State:
- Created 2 years ago
- Reactions:9
- Comments:24 (3 by maintainers)
I just ran into the same issue, it caught me completely off guard. @ospfranco I’ve found this seems to work too. Not sure if it’s the right / best way to use the
off
/on
methods. 🤷This was very hard to find. Please add this to the quickStart docs?