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只会在初始化执行一次,因此不会改变

相关推荐
weixin_382395235 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__5 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.6 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~7 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华7 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子10 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅10 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni10 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学11 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端