本文为开发开源项目的真实开发经历,感兴趣的可以来给我的项目点个star,谢谢啦~
详细博文先容:开源|Documind协同文档(接入deepseek-r1、支持实时聊天)
前置代码
zustand界说
- import {create} from "zustand";
- import {type Editor} from "@tiptap/react"
- interface EditorState{
- editor:Editor | null;
- setEditor:(editor:Editor|null)=>void;
- }
- export const useEditorStore = create<EditorState>()((set)=>({
- editor:null,
- setEditor:(editor)=>set({editor}),
- }))
复制代码 editor生存设置
这里为editor的生命周期,及editor总会实时生存到zustand中
- onCreate({ editor }) {
- setEditor(editor);
- },
- onDestroy() {
- setEditor(null);
- },
- onUpdate({ editor }) {
- setEditor(editor);
- },
- onSelectionUpdate({ editor }) {
- setEditor(editor);
- },
- onTransaction({ editor }) {
- //事务更新时,将编辑器设置到全局状态中
- setEditor(editor);
- },
- onFocus({ editor }) {
- //聚焦时,将编辑器设置到全局状态中
- setEditor(editor);
- },
- onBlur({ editor }) {
- //失去焦点时,将编辑器设置到全局状态中
- setEditor(editor);
- },
- onContentError({ editor }) {
- setEditor(editor);
- },
复制代码 正文-ImageButton 组件
这里我为tiptap文本编辑器界说了一个图片文件,这里的逻辑就是点击CldUploadButton组件后在当地选择图片,选择图片后上传到cloudinary服务器成功之后触发onSuccess绑定的uploadPhoto事件,此中result?.info?.secure_url就是上传图片的云地点,将此地点传入onChange即可在tiptap文本编辑器中添加图片。
而在使用的过程中碰到了一个题目,下面代码中的console.log(editor)打印结果不一样,第一个打印为正常editor对象,而第二个console.log(editor)打印却是null,这就是由闭包捕获造成的。
为什么zustand总会实时生存editor状态还会打印null?因为editor在初始渲染为null的时间就被onChange()捕获,这个时间onChange()闭包内的editor就被赋值为null我将这里的editor引用取名为editor-1;之后editor的生命周期会实时触发zustand生存最新的editor状态(可参考前置代码),这个时间const { editor } = useEditorStore();中的editor则为最新的editor状态,我给其取名editor-2。editor-1是旧引用而editor-2是新引用,由于onChange()是个闭包,以是由于闭包捕获机制,闭包捕获并生存的是旧引用editor-1,而获取不到新引用editor-2,以是闭包内的console.log会打印null。
- import { useEditorStore } from "@/store/use-editor-store";
- import { ImageIcon } from "lucide-react";
- import { CldUploadButton } from "next-cloudinary";
- export const ImageButton = () => {
- const { editor } = useEditorStore();//来自zustand
- console.log(editor) //打印为最新editor对象
- const onChange = (src: string) => {
- console.log(editor) //打印为null
- editor?.chain().focus().setImage({ src }).run();
- };
- const uploadPhoto = (result: any) => {
- onChange(result?.info?.secure_url);
- };
- return (
- <div className="flex flex-col items-center justify-center">
- //cloudinary云图片上传组件
- <CldUploadButton
- options={{ maxFiles: 1 }}
- onSuccess={uploadPhoto}
- uploadPreset="kdm7bzdm"
- >
- <ImageIcon className="size-4" />
- </CldUploadButton>
- </div>
- );
- };
复制代码 办理方案
直接在闭包函数内获取到当前zustand中的最新editor对象,这样我们就有效办理了闭包捕获题目。
- import { useEditorStore } from "@/store/use-editor-store";
- import { ImageIcon } from "lucide-react";
- import { CldUploadButton } from "next-cloudinary";
- import { useCallback } from "react";
- export const ImageButton = () => {
- const onChange = (src: string) => {
- console.log(editor);//打印为最新editor对象
- const currentEditor = useEditorStore.getState().editor;
- currentEditor?.chain().focus().setImage({ src }).run();
- }
- const uploadPhoto = (result: any) => {
- onChange(result?.info?.secure_url);
- };
- return (
- <div className="flex flex-col items-center justify-center">
- {/* 图片插入下拉菜单 */}
- <CldUploadButton
- options={{ maxFiles: 1 }}
- onSuccess={uploadPhoto}
- uploadPreset="kdm7bzdm"
- >
- <ImageIcon className="size-4" />
- </CldUploadButton>
- </div>
- );
- };
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |