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

React-Quill中Enter键自定义Action失败且浏览器崩溃问题排查

问题描述

我使用React-Quill构建了一个聊天输入框,希望修改Enter键的默认行为——将原本的换行操作改为分发一个action,但尝试后未能实现预期效果。即使对modules进行memo化处理也没有解决问题,且调用组件内的普通函数时浏览器会出现崩溃情况。

相关代码如下:

function Editor() {
  const [code, setCode] = useState("initial text");
  const [fakeStore, fakeDispatch] = useState("nothing");

  const send = (text) => {
    fakeDispatch(text);
  };

  const modulesSend = {
    keyboard: {
      bindings: {
        custom: {
          key: "Enter",
          handler: send,
        },
      },
    },
  };

  const memoModulesSend = useMemo(
    () => ({
      keyboard: {
        bindings: {
          custom: {
            key: "Enter",
            handler: send,
          },
        },
      },
    }),
    [],
  );

  const handleProcedureContentChange = (content, delta, source, editor) => {
    setCode(content);
  };

  return (
    <>
      <p>{fakeStore}</p>
      1
      <ReactQuill
        theme="snow"
        modules={modulesSend}
        onChange={handleProcedureContentChange}
      />
      2
      <ReactQuill
        theme="snow"
        defaultValue={code}
        modules={memoModulesSend}
        onChange={handleProcedureContentChange}
      />
    </>
  );
}

崩溃原因与修复方案

核心崩溃原因

  1. 未阻止Enter键默认行为:绑定的Enter键handler没有返回false,Quill会继续执行默认换行逻辑,触发onChange后调用setCode更新状态,组件频繁重新渲染。同时modulesSend每次渲染都是新对象,React-Quill会反复初始化编辑器,形成渲染循环导致浏览器卡死。
  2. 闭包与参数误解:memoModulesSend的依赖数组为空,内部引用的send是初始渲染时的闭包,无法访问最新的fakeDispatch;且send接收的参数并非编辑器文本,而是Quill键盘事件的range对象,调用fakeDispatch(range)会导致状态更新异常,加剧循环问题。

修复后的代码

import React, { useState, useMemo, useCallback } from 'react';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';

function Editor() {
  const [code, setCode] = useState("initial text");
  const [fakeStore, fakeDispatch] = useState("nothing");

  // 用useCallback稳定send函数引用
  const send = useCallback((content) => {
    fakeDispatch(content);
    setCode(""); // 发送后清空输入框
  }, [fakeDispatch]);

  // 正确memo化modules,依赖包含send
  const memoModulesSend = useMemo(() => ({
    keyboard: {
      bindings: {
        sendMessage: {
          key: "Enter",
          // handler接收range和context参数,context包含编辑器实例
          handler: (range, context) => {
            const plainText = context.editor.getText().trim();
            if (plainText) {
              send(plainText);
            }
            // 返回false阻止Quill默认换行行为
            return false;
          },
        },
      },
    },
  }), [send]);

  const handleProcedureContentChange = (content) => {
    setCode(content);
  };

  return (
    <>
      <p>{fakeStore}</p>
      <ReactQuill
        theme="snow"
        value={code}
        modules={memoModulesSend}
        onChange={handleProcedureContentChange}
      />
    </>
  );
}

export default Editor;

关键修复点

  • 使用useCallback包裹send函数,确保其引用稳定,作为memo化modules的依赖。
  • 键盘绑定的handler正确接收Quill的range和context参数,通过context.editor获取编辑器内容,避免参数误解。
  • handler返回false,彻底阻止Quill的默认换行行为,避免触发不必要的onChange。
  • memo化modules时添加正确的依赖(send),防止编辑器频繁重新初始化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:28:10