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

如何正确实现React Quill自定义工具栏的条件渲染?

React Quill自定义工具栏隐藏后无法重新渲染的解决办法

问题说明

在使用React Quill自定义工具栏时,通过isOpen状态控制工具栏的显示与隐藏。但切换isOpen为false后再设为true,带有id="toolbar"的工具栏按钮区域无法正常渲染,仅右侧的操作按钮能显示。

原因分析

  1. 组件重复定义:CustomToolbar被定义在OpinionInput组件内部,每次父组件渲染都会重新创建这个组件,导致DOM元素被重新生成。而ReactQuill实例初始化时只会绑定一次#toolbar容器,新生成的容器无法被已存在的Quill实例识别。
  2. 显示控制方式不当:使用display: none仅隐藏DOM而非卸载组件,再次显示时Quill不会重新初始化工具栏的绑定关系,导致按钮无法正常工作。

解决方案

方案一:调整组件结构+条件渲染+强制重新初始化

将工具栏组件移到外部,用条件渲染控制挂载/卸载,并给ReactQuill加key强制重新渲染,让Quill重新绑定工具栏:

import { useState } from 'react';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import './OpinionInput.css';

const OPINION_PLACEHOLDER = 'Qual sua opinião?';

// 移到组件外部定义,避免重复创建
const CustomToolbar = ({ onClose }) => {
  return (
    <div className="flex justify-between items-center">
      <div id="toolbar">
        <button className="ql-bold"></button>
        <button className="ql-italic"></button>
      </div>

      <div className="space-x-3">
        <button
          className="ql-custom text-grey-500 text-center focus:outline-none hover:text-grey-700 hover:bg-grey-100"
          onClick={onClose}
        >
          Cancelar
        </button>

        <button className="bg-brandGreen text-greys-0 px-3 py-1 rounded-full">
          Opinar
        </button>
      </div>
    </div>
  );
};

export default function OpinionInput() {
  const [isOpen, setIsOpen] = useState(false);
  const [value, setValue] = useState('');
  
  const handleOpen = () => {
    setIsOpen(true);
  };

  const handleClose = () => {
    setIsOpen(false);
  };

  return (
    <div className="flex flex-col">
      {/* 条件渲染用户信息栏 */}
      {isOpen && (
        <div className="flex flex-row items-center space-x-2">
          <div className="w-8 h-8 bg-brandGreen rounded-full"></div>
          <span className="text-body-medium">Pedro Silva</span>
        </div>
      )}

      <ReactQuill
        key={isOpen} // 用isOpen作为key,状态变化时强制重新渲染组件
        theme="snow"
        value={value}
        onChange={setValue}
        placeholder={OPINION_PLACEHOLDER}
        modules={{
          toolbar: { container: '#toolbar' },
        }}
        onFocus={handleOpen}
      />

      {/* 条件渲染工具栏,替代display:none */}
      {isOpen && <CustomToolbar onClose={handleClose} />}
    </div>
  )
}

方案二:使用ReactQuill内置工具栏配置(更推荐)

直接通过ReactQuill的toolbar配置数组自定义工具栏,避免手动操作DOM容器,更符合React组件化思想:

import { useState } from 'react';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import './OpinionInput.css';

const OPINION_PLACEHOLDER = 'Qual sua opinião?';

export default function OpinionInput() {
  const [isOpen, setIsOpen] = useState(false);
  const [value, setValue] = useState('');
  
  const handleOpen = () => {
    setIsOpen(true);
  };

  const handleClose = () => {
    setIsOpen(false);
  };

  // 自定义工具栏配置,整合默认按钮和自定义操作按钮
  const toolbarOptions = [
    ['bold', 'italic'],
    // 指定自定义按钮的容器
    [{ container: '#custom-toolbar-actions' }]
  ];

  return (
    <div className="flex flex-col">
      {isOpen && (
        <div className="flex flex-row items-center space-x-2">
          <div className="w-8 h-8 bg-brandGreen rounded-full"></div>
          <span className="text-body-medium">Pedro Silva</span>
        </div>
      )}

      <ReactQuill
        theme="snow"
        value={value}
        onChange={setValue}
        placeholder={OPINION_PLACEHOLDER}
        modules={{ toolbar: toolbarOptions }}
        onFocus={handleOpen}
      />

      {isOpen && (
        <div id="custom-toolbar-actions" className="flex justify-end space-x-3 mt-2">
          <button
            className="ql-custom text-grey-500 text-center focus:outline-none hover:text-grey-700 hover:bg-grey-100"
            onClick={handleClose}
          >
            Cancelar
          </button>

          <button className="bg-brandGreen text-greys-0 px-3 py-1 rounded-full">
            Opinar
          </button>
        </div>
      )}
    </div>
  )
}

方案二无需手动处理DOM绑定问题,完全依托ReactQuill的原生能力实现自定义,能有效避免类似的渲染bug。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 22:42:05