sunpl13
sunpl13

Reputation: 197

How to upload image inside React-Quill Content?

I'm making a bulletin board with React-Quill. However, when I upload an image, the image does not come out from inside the Content. And when checking with console.log, the image url is empty. What part is wrong?

function Post() {

  const   QuillRef = useRef<ReactQuill>()
  const [Title, setTitle] = useState("")  
  const [contents, setcontents] = useState("")    

  const imageHandler = () => {
    const input = document.createElement("input");
    const formData = new FormData();


    input.setAttribute("type", "file");
    input.setAttribute("accept", "image/*");
    input.click();

    input.onchange = async () => {
      const file : any = input.files;
      if (file !== null) {
        formData.append("image", file[0]);

        console.log(formData)
      }
    }
  }
  const titleHandler = (e : React.ChangeEvent<HTMLTextAreaElement>) => {
      e.preventDefault()
      setTitle(e.currentTarget.value)
  }


  return (
    <div className="post">
        <ReactQuill
        style = {{height : "650px"}}
          ref = {(element) => {
            if(element != null) {
              QuillRef.current = element
            }
          }}
          value = {contents || ""}
          onChange = {(content, delta, source, editor) => setcontents(editor.getHTML())}
          modules = {modules}
          formats = {formats}
          theme = "snow"
          placeholder = "내용을 입력해주세요"/>
    </div>
  );
}

export default Post;

I tried several ways, but failed. What is the workaround??

Upvotes: 1

Views: 19648

Answers (3)

İsmail Can Karataş
İsmail Can Karataş

Reputation: 77

npm i quill-image-uploader --legacy-peer-deps

import { useState } from 'react';
import ReactQuill, { Quill } from 'react-quill';
import ImageUploader from 'quill-image-uploader';
import 'react-quill/dist/quill.snow.css'

const ComponentName = () => {
    const [value, setValue] = useState('');
    Quill.register('modules/imageUploader', ImageUploader);

    return (
        <ReactQuill
            theme="snow"
            modules={{
                toolbar: ['image'],
                imageUploader: {
                    upload: (file) =>
                        new Promise((resolve, reject) => {
                            // const formData = new FormData();
                            // formData.append('image', file);
                            console.log(file);
                        })
                }
            }}
            value={value}
            onChange={(e) => setValue(e)}
        />
    );
};

Upvotes: 0

wen83
wen83

Reputation: 53

useRef does not work in dynamic import use this instead:

const QuillNoSSRWrapper = dynamic(
  async () => {
    const { default: RQ } = await import('react-quill');
    // eslint-disable-next-line react/display-name
    return ({ forwardedRef, ...props }) => <RQ ref={forwardedRef} {...props} />;
  },
  { ssr: false }
);

and then the jsx:

<QuillNoSSRWrapper
  forwardedRef={quillRef}
  ...
/>

sample handler:

const quillImageCallback = async () => {
    const input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.setAttribute('accept', 'image/*');
    input.click();

    input.onchange = async () => {
      const file = input.files ? input.files[0] : null;
      let data = null;
      const formData = new FormData();

      const quillObj = quillRef?.current?.getEditor();
      const range = quillObj?.getSelection();

      if (file) {
        formData.append('file', file);
        formData.append('resource_type', 'raw');

        const responseUpload = await fetch(
          `${process.env.NEXT_PUBLIC_IMAGE_UPLOAD}/upload`,
          { method: 'POST', body: formData }
        );

        data = await responseUpload.json();
        if (data.error) {
          console.error(data.error);
        }

        quillObj.editor.insertEmbed(range.index, 'image', data?.secure_url);
      }
    };
  };

Upvotes: 4

Ismail Hosen
Ismail Hosen

Reputation: 206

import { Grid } from '@mui/material';
import React, { useMemo, useRef } from 'react'
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import { ImageUpload } from 'services/image/ImageUpload';
import { ErrorToast } from 'utils';
import '../../assets/css/richTextEditor.css' // just for custom css

export default function FormikRichText({ id, label, value, setValue }) {

  const quillRef = useRef();
  
  const imageHandler = (e) => {
    const editor = quillRef.current.getEditor();
    console.log(editor)
    const input = document.createElement("input");
    input.setAttribute("type", "file");
    input.setAttribute("accept", "image/*");
    input.click();

    input.onchange = async () => {
      const file = input.files[0];
      if (/^image\//.test(file.type)) {
        console.log(file);
        const formData = new FormData();
        formData.append("image", file);
        const res = await ImageUpload(formData); // upload data into server or aws or cloudinary
        const url = res?.data?.url;
        editor.insertEmbed(editor.getSelection(), "image", url);
      } else {
        ErrorToast('You could only upload images.');
      }
    };
  }
  const modules = useMemo(() => ({
    toolbar: {
      container: [
        [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
        ['bold', 'italic', 'underline', "strike"],
        [{ 'list': 'ordered' }, { 'list': 'bullet' },
        { 'indent': '-1' }, { 'indent': '+1' }],
        ['image', "link",],
        [{ 'color': ['#000000', '#e60000', '#ff9900', '#ffff00', '#008a00', '#0066cc', '#9933ff', '#ffffff', '#facccc', '#ffebcc', '#ffffcc', '#cce8cc', '#cce0f5', '#ebd6ff', '#bbbbbb', '#f06666', '#ffc266', '#ffff66', '#66b966', '#66a3e0', '#c285ff', '#888888', '#a10000', '#b26b00', '#b2b200', '#006100', '#0047b2', '#6b24b2', '#444444', '#5c0000', '#663d00', '#666600', '#003700', '#002966', '#3d1466'] }]
      ],
      handlers: {
        image: imageHandler
      }
    },
  }), [])
  return (
    <>
      <Grid container>
        <Grid item md={3} xs={12} sx={{ display: 'flex', justifyContent: 'start', alignItems: 'center', pr: 2 }}>
          <label htmlFor={id} className='text-end'>{label} :</label>
        </Grid>
        <Grid item md={9} xs={12}>

          <ReactQuill theme="snow" ref={quillRef} value={value} modules={modules} onChange={setValue} />

        </Grid>
      </Grid>
    </>

  )
}

And the main index.js file

import FormikRichText from 'components/Input/FormikRichText';
import React, { useState } from 'react'

const index = () => {
    const [value, setValue] = useState("");
    return (
        <>
            <FormikRichText
                id="description"
                name="description"
                label="Description"
                value={value}
                setValue={setValue}
            />
        </>
    )
}

export default index

Upvotes: 3

Related Questions