Reputation: 197
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
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
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
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