본문 바로가기
Front-end/React

react-quill 리액트 글쓰기 에디터 이미지 서버에 저장후 url 연결 하기 [base64 문제 해결 too large data]

by 꼬바리 2023. 8. 11.

react-quill을 사용해서 글 내에 이미지를 삽입하면

자동으로 base64변환해서 사이즈가 커진다.

 

이미지 핸들러를 이용하여 이미지를 서버나 클라우드에 저장하고 url을 사용하여 

<img src="" /> 

String으로 저장되는 contents의 크기를 줄이기로했다.

import React, { useEffect, useMemo, useRef, useState } from "react"
import ReactQuill , {Quill} from "react-quill"
import '../../assets/css/quill.snow.css'

quill 을 사용할떄 필요한 기본 들만 임포트 해줘도 충분하다.

const quillRef = useRef(null);

    useEffect(() => {
        const quill = quillRef.current;
        // console.log(quill);

        const handleImage = () => {
            // 이미지 핸들 로직
            const input = document.createElement("input");
            input.setAttribute("type", "file");
            input.setAttribute("accept", "image/*");
            input.click();

            input.onchange = async () => {
                const file = input.files[0];

                // 현재 커서 위치 저장
                // const range = getEditor().getSelection(true);
                const range = quill.selection

                // 서버에 올려질때까지 표시할 로딩 placeholder 삽입
                quill.getEditor().insertEmbed(range.index, "image", `/images/loading.gif`);
                
                
                try {
                    // S3에 업로드 한뒤 이미지 태그에 삽입할 url을 반환받도록 구현
                    const formData = new FormData();
                    formData.append('file' , file)
                    const result = await actionUploadEditorImage(formData); 
                    const url = result.data
                    console.log(url);
                    // 정상적으로 업로드 됐다면 로딩 placeholder 삭제
                    quill.getEditor().deleteText(range.index, 1);
                    // 받아온 url을 이미지 태그에 삽입
                    quill.getEditor().insertEmbed(range.index, "image", url);
                    
                    // 사용자 편의를 위해 커서 이미지 오른쪽으로 이동
                    quill.getEditor().setSelection(range.index + 1);
                } catch (e) {
                    quill.getEditor().deleteText(range.index, 1);
                }
            };
        }
        
        if (quillRef.current) {
            // const { getEditor } = quillRef.current;
            const toolbar = quill.getEditor().getModule("toolbar");
            toolbar.addHandler("image", handleImage);
        }
    }, []);

아래 블로그를 참고하여 작업하였다.

 

동작은 이러하다.

1. [프론트] 이미지 삽입

2. [프론트]  로딩gif 삽입

3. [서버] 이미지 url 추출 (나의 경우 S3에 업로드후 url 생성했다)

4. [프론트]  로딩gif삭제

5. [프론트] 서버에서 받은 url 로 이미지 태그에 삽입

 

base64 로 5천만줄 되던 String값이 img태그 하나로 줄어드는 매직이된다.

참고블로그

    const toolbarOptions = [
        // [{ 'font': [] }],    //웹사이즈 기본폰트를 사용하기위해 제거
        [{ header: "1" }, { header: "2" }, { 'header': [1, 2, 3, 4, false] }],
        ['bold', 'italic', 'underline','strike'],
        [{ 'color': [] }, { 'background': [] }],
        [{'list': 'ordered'}, {'list': 'bullet'}, {'list': 'check'}],
        [{'indent': '-1'}, {'indent': '+1'}],
        [{ 'align': [] } , { direction: "rtl" }],
        ['link' , 'image'],
        ["code-block"],
        [{ script: "sub" }, { script: "super" }],
        [{ table: true }]
    ]
    const formats = [
        // 'font',
        'header',
        'bold', 'italic', 'underline', 'strike',
        'color', 'background',
        'list', 'bullet', ,'check',
        'indent',
        'align', 'direction',
        'link', 'image',
        "code-block",
        "script",
        "table",
    ]

    const modules = useMemo(()=>{
        return {
            // table: true,
            // tableUI: true,
            toolbar: {
                container: toolbarOptions,
            },
            // ImageResize: { modules: ['Resize'] },
            imageDrop: true,
            clipboard: {
                matchVisual: false              // toggle to add extra line breaks when pasting HTML:
            },

        }
    })

모듈에 ImageResize: { modules: ['Resize'] },

설정해주지 않아도 핸들링 가능하다.

되려 나는 모듈에 설정해서 오류가났다 delta가 없다나?

<ReactQuill
    id={id}
    ref={quillRef}
    className="form-control text-editor"
    theme = 'snow'
    modules = {modules}
    formats = {formats}
    value = {value || ''}
    onChange = {(content, delta, source, editor) => setVlaue(editor.getHTML())}
    style = {{width: '100%'}}
    readOnly={isDisable}
/>

HTML 코드는 위와 같다.

 

 

728x90
반응형

댓글