You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Next.js + TypeScript项目中React Quill自定义图片处理器的类型与Ref引用问题求助

Fixing TypeScript & Ref Issues with react-quill in Next.js

I’ve run into nearly identical headaches using react-quill with TypeScript in Next.js, so let’s walk through fixing your ref and type problems step by step:

1. Add Proper Type Dependencies

First, make sure you have type support for both react-quill and the underlying Quill editor. While react-quill v2+ includes built-in types, you’ll still need @types/quill for full editor instance type safety:

npm install @types/quill --save-dev
# or
yarn add @types/quill --dev

2. Fix Dynamic Import Type

When using next/dynamic, the imported component loses type information by default. We’ll explicitly type it using react-quill’s built-in ReactQuillProps:

import type { ReactQuillProps } from 'react-quill';

const ReactQuill = dynamic<ReactQuillProps>(import('react-quill'), {
  ssr: false,
  loading: () => <p>Loading ...</p>,
});

3. Type the Ref Correctly

Ditch the any type for your ref—instead, type it to match the react-quill component instance, which exposes the getEditor() method that returns a Quill instance:

import Quill from 'quill';

// ...

const quillRef = useRef<{ getEditor: () => Quill }>(null);

4. Clean Up Type Annotations in imageHandler

Replace loose any types with proper TypeScript types for the file input and handle null cases safely:

const imageHandler = async () => {
  const input = document.createElement('input');
  input.setAttribute('type', 'file');
  input.setAttribute('accept', 'image/*');
  input.click();
  
  input.onchange = async () => {
    const file = input.files?.[0] as File | null;
    if (!file) return; // Guard clause to avoid null errors
    
    const formData = new FormData();
    formData.append("file", file);
    
    if (quillRef.current) {
      const quillObj = quillRef.current.getEditor();
      // Now you get full type support for Quill methods here
      // Example: After uploading, insert the image into the editor:
      // const imageUrl = await yourUploadAPI(formData);
      // const range = quillObj.getSelection();
      // if (range) quillObj.insertEmbed(range.index, 'image', imageUrl);
    }
  };
}

Full Modified Code

Here’s the complete fixed version of your component:

import React, { useState, useRef } from 'react';
import dynamic from 'next/dynamic';
import { Container } from "@mui/material";
import type { ReactQuillProps } from 'react-quill';
import Quill from 'quill';
import 'react-quill/dist/quill.snow.css';

const ReactQuill = dynamic<ReactQuillProps>(import('react-quill'), {
  ssr: false,
  loading: () => <p>Loading ...</p>,
});

const Editor = () => {
  const [value, setValue] = useState('');
  const quillRef = useRef<{ getEditor: () => Quill }>(null);

  const imageHandler = async () => {
    const input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.setAttribute('accept', 'image/*');
    input.click();
    
    input.onchange = async () => {
      const file = input.files?.[0] as File | null;
      if (!file) return;
      
      const formData = new FormData();
      formData.append("file", file);
      
      if (quillRef.current) {
        const quillObj = quillRef.current.getEditor();
        // Add your file upload logic here, then insert the image into the editor
      }
    };
  };

  const modules = {
    toolbar: {
      container: [
        [{ font: [] }, { 'size': [] }, { 'header': [1, 2, 3, 4, 5, 6] }],
        ['bold', 'italic', 'underline', 'strike'],
        [{ 'color': [] }, { 'background': [] }],
        [{ 'script': 'sub' }, { 'script': 'super' }],
        [{ 'header': 1 }, { 'header': 2 }, 'blockquote', 'code-block'],
        [
          { list: 'ordered' }, { list: 'bullet' },
          { indent: '-1' }, { indent: '+1' },
        ],
        [{ 'direction': 'rtl' }, { 'align': [] }],
        ['link', 'image', 'clean'],
      ],
      handlers: {
        image: imageHandler
      }
    }
  };

  return (
    <Container maxWidth="xxxl" disableGutters>
      <ReactQuill
        ref={quillRef}
        value={value}
        modules={modules}
        onChange={setValue}
        placeholder="Start typing!"
      />
    </Container>
  );
};

export default Editor;

Key Fixes Explained

  • Typed Dynamic Import: Ensures the ReactQuill component has all correct prop types, so you get autocompletion and type checking for props like modules or onChange.
  • Typed Ref: Eliminates unsafe any types and gives you full type support for the Quill editor instance returned by getEditor().
  • Type-Safe File Handling: Adds a guard clause to handle null file cases and properly types the file object, preventing runtime errors.

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

火山引擎 最新活动