react-quill使用服务端上传图片handlers导致中文输入问题-原理分析

背景

富文本编辑器:react-quill

当服务端的方法上传图片时,导致输入问题

打字时,导致打一个英文,失焦,而打中文字时,则导致只能打出拼音的第一个字母,中文出不来

解释:用服务端上传图片而不是默认的base64,需要用handlers

现象

1.如果有handlers,且onChange里面用了setState或者dispatch,会导致打字有问题

2.如果handlers去掉,打字没问题

3.handers绑定的image函数为空函数,打字还是有问题

4.有handlers,但是没有重新触发渲染(setState、dispatch),打字没问题

问题代码

Class写法

js 复制代码
<ReactQuill
        ref={ref => {this.state.myRef = ref}}
        style={{height:'120px'}}
        key='detail'
        theme="snow"
        modules={
          {
            toolbar: {
              container: this.state.container,
              handlers: {
                image: () => this.imageHandler()
              }
            },
            clipboard: {
              // toggle to add extra line breaks when pasting HTML
              matchVisual: false,
            }
          }
        }
        value={this.props.default || ''}
        onChange={this.handleChange}
      />

handleChange里面如果用setState或者dispatch(设置store) Hook写法

js 复制代码
function 业务组件(){
    const imageHandler = () => {
      //服务端上传图片
    }
    return (
        <ReactQuill
            ref={quillRef}
            value={tourBasicObj.detailIntroductionContent || ''}
            placeholder="请输入介绍内容"
            onChange={value => handleDetailIntroductionContentChange(value)}
            style={{ width: 385 }}
            modules={{
                toolbar: {
                  container,
                  handlers: {
                    image: imageHandler,
                  },
                },
              }
            }
          />

    )

}

初步猜测

是因为重新render导致quill库认为重新绑定hander,进而重新初始化,因此失焦

寻找根因

源代码结构

1.业务代码使用react-quill

2.react-quill库使用quill,作用是把quill适配成react可以用的库

3.quill才是富文本编辑器的库,富文本编辑功能都在此

第一步

排查为什么有了handlers,且onChange里面有了setState,即使handlers挂载空函数,也会导致失焦

根据ai提示与react-quill源码阅读,猜测可能是由于有了handlers,导致modules改变,进而触发某种重载

为什么onChange里面有了setState,就会有问题

这是由于setState会触发render,重新加载组件

react-quill源码截图

因此尝试调试排查,是因为重新渲染的时候,由于有了handlers,所以导致modules不同吗

本地调试代码模拟如下

父组件

子组件

打一个字,触发setState,导致重新渲染(模拟打字场景)

打印结果

由此结果证明

有了handlers,会导致modules发生变化

第二步

由于有了handlers改变,导致modules发生改变,那么我们需要在源码中寻找答案,由于modules改变,是触发了handers重新挂在或者整个编辑器重新加载

通过在源码里面加console的方法,调试得出结论

由于modules改变,导致触发了unhookEdtior和createEditor,因此导致失焦

调试结果

没有handlers

有handlers

对比得出关键代码,有handlers会触发unhookEditor和createEditor

源码中关键代码截图与解释

1.在生命周期钩子componentWillReceiveProps里面会调用shouldComponentRegenerate,会判断是否为true

2.由于有了handlers,会导致modules不同,因此为true

3.由于为true,因此调用regenerate方法

4.generation方法导致generation状态更新

5.在生命周期钩子componentWillUpdate会判断,generation是否一致,由于状态已经更新,因此不一致,所以调用componentWillUnmount

在componentWillUnmount会触发unhookEdit,导致富文本编辑器失去监听

于是有了答案,由于hanlder,导致modules更新,进而触发unhookEditor和createEditor也就是编辑器重载,因此失焦,编辑器渲染之后是不会主动聚焦的,所以也就解释了为什么输入一个中文,就变成拼音且失焦,输了一个英文字母,就失焦

第三步

探寻为什么有了handlers,会导致modules更新

通过再次复习react,发现答案

如果是函数式写法,发现只要setState,就会触发render,render的时候就会触发所有方法的重载,如果不想要方法重载,就必须用特殊方法,例如把方法放到函数组件外等

如果是Class写法,由于绑定的函数需要用到this或者this.setState,一般来说必须用bind(this)或者用箭头函数,但是如果用了箭头函数,render的时候,就会导致加载了新的方法

结论

根因:由于打字后,onChange里面有setState,触发重新render,导致imageHandler重新定义,最终传给react-quill组件的时候,导致modules发生了变化,最后触发了取消监听editor,再监听editor,进而导致不聚焦(取消监听并重新注册的这个间隙,浏览器会认为编辑区失去了活动状态(尤其是 IME 输入法正在 composition 中时)------这就是失焦发生的地方)

解决方案

Hook函数式写法

1. useMemo

由于useMemo对整个modules做了缓存,保证modules不会发生改变,因此不会触发editor的卸载与重载,进而保持打字正常

2.useRef

3.useCallback

单独对image做useCallback也可以

imageHandlerCb = useCallback(imageHandler,[]);

总而言之,是因为handlers导致modules改变,因此只要让handlers不改变或者modules不改变即可

Class写法

由于modules用的是this.modules,而this.modules只会在初始化执行一次,因此不会改变

相关推荐
wuhen_n6 小时前
JavaScript链表与双向链表实现:理解数组与链表的差异
前端·javascript
wuhen_n7 小时前
JavaScript数据结构深度解析:栈、队列与树的实现与应用
前端·javascript
狗哥哥7 小时前
微前端路由设计方案 & 子应用管理保活
前端·架构
前端大卫7 小时前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘8 小时前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare8 小时前
浅浅看一下设计模式
前端
Lee川8 小时前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix8 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人8 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl8 小时前
OpenClaw 深度技术解析
前端