You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QuillJS selection-change事件回调缓存变量导致状态值不更新如何解决

问题原因

这是典型的React闭包陷阱问题,和Quill事件缓存无关:你当前的useEffect仅设置了quill作为依赖项,只会在quill实例初始化时执行一次,内部注册的selection-change事件回调会捕获作用域内的初始documentState快照,后续documentState更新后,回调内访问的依旧是初始化时的旧值。


解决方案

方案1:补充依赖项+添加事件清理逻辑

把相关状态加入依赖数组,同时在useEffect返回值中添加事件解绑逻辑,避免重复注册事件:

useEffect(() => {
  if (!quill) return
  quill.clipboard.dangerouslyPasteHTML(documentContent);
  
  const handleTextChange = () => {
    setDocumentContent(quill.root.innerHTML);
  }
  const handleSelectionChange = (range, oldRange, source) => {
    console.log(documentState?.predictionStatus, range, oldRange, source);
  }

  quill.on('text-change', handleTextChange);
  quill.on('selection-change', handleSelectionChange);

  // 依赖变化时清理旧事件监听器
  return () => {
    quill.off('text-change', handleTextChange);
    quill.off('selection-change', handleSelectionChange);
  }
}, [quill, documentState, documentContent]);

方案2:用useRef存储最新状态,避免重复绑定事件

如果不想频繁触发Quill事件的解绑/绑定,可以用ref同步最新的状态值:

// 组件内声明ref同步最新的documentState
const documentStateRef = useRef(documentState);
// 每次documentState更新时同步ref的值
useEffect(() => {
  documentStateRef.current = documentState;
}, [documentState]);

// 原quill初始化useEffect仅需修改回调取值逻辑
useEffect(() => {
  if (quill) {
    quill.clipboard.dangerouslyPasteHTML(documentContent);
    quill.on('text-change', () => {
      setDocumentContent(quill.root.innerHTML);
    });

    quill.on('selection-change', (range, oldRange, source) => {
      // 读取ref的最新值,不受闭包影响
      console.log(documentStateRef.current?.predictionStatus, range, oldRange, source);
    })
  }
}, [quill, documentContent]);

该方案只会在quill初始化时注册一次事件,性能开销更低。


内容的提问来源于stack exchange,提问作者Shamoon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 10:27:08