승섭 8/7

섭승이·2023년 8월 7일
0
post-custom-banner

React-quill 이미지 다루기

React-quill 라이브러리를 통해 에디터 기능을 구현하였고, 이 중 이미지를 처리하는 함수를 만들어야 된다. 그 이유로는 그냥 이미지를 넣어주면 base64로 변환된 이미지가 너무 길어서 서버에 저장되지 않는 문제가 발생하기 때문이다.
따라서 이미지 태그의 src에 base64 대신 url을 넣어주어야 한다.

// 이미지 처리를 하는 핸들러
  const imageHandler = () => {
    // 1. 이미지를 저장할 input type=file DOM을 만든다.
    const input = document.createElement("input");
    // 속성 써주기
    input.setAttribute("type", "file");
    input.setAttribute("accept", "image/*");
    input.click(); // 에디터 이미지버튼을 클릭하면 이 input이 클릭된다.
    // input이 클릭되면 파일 선택창이 나타난다.

    // input에 변화가 생긴다면 = 이미지를 선택
    input.addEventListener("change", async () => {
      if (input.files && input.files.length > 0) {
        const file = input.files[0];
        // multer에 맞는 형식으로 데이터 만들어준다.
        const formData = new FormData();
        formData.append("file", file); // formData는 키-밸류 구조
        // 백엔드 multer라우터에 이미지를 보낸다.
        try {
          const result = await axios.post("/api/upload", formData, {
            headers: {
              "Content-Type": "multipart/form-data", // 중요: 멀티파트(form-data) 형식으로 보내기 위해 헤더 설정
            },
          });
          const IMG_URL = result.data;
          // 이 URL을 img 태그의 src에 넣은 요소를 현재 에디터의 커서에 넣어주면 에디터 내에서 이미지가 나타난다
          // src가 base64가 아닌 짧은 URL이기 때문에 데이터베이스에 에디터의 전체 글 내용을 저장할 수있게된다
          // 이미지는 꼭 로컬 백엔드 uploads 폴더가 아닌 다른 곳에 저장해 URL로 사용하면된다.

          // 이미지 태그를 에디터에 써주기 - 여러 방법이 있다.
          const editor = quillRef.current.getEditor(); // 에디터 객체 가져오기
          // 1. 에디터 root의 innerHTML을 수정해주기
          // editor의 root는 에디터 컨텐츠들이 담겨있다. 거기에 img태그를 추가해준다.
          // 이미지를 업로드하면 -> 멀터에서 이미지 경로 URL을 받아와 -> 이미지 요소로 만들어 에디터 안에 넣어준다.
          // editor.root.innerHTML =
          //   editor.root.innerHTML + `<img src=${IMG_URL} /><br/>`; // 현재 있는 내용들 뒤에 써줘야한다.
          if (editor) {
            // 2. 현재 에디터 커서 위치값을 가져온다
            const range = editor.getSelection();
            // 가져온 위치에 이미지를 삽입한다
            editor.insertEmbed(range.index, "image", IMG_URL[0]);
            editor.setSelection(range.index + 1);
          }
        } catch (error) {
          console.log("실패했어요ㅠ");
        }
      }
    });
  };

이 코드가 이미지를 처리하는 함수로 자세한 설명은 주석으로 달아놓았으니 생략하겠다.

const result = await axios.post("/api/upload", formData, {
            headers: {
              "Content-Type": "multipart/form-data", // 중요: 멀티파트(form-data) 형식으로 보내기 위해 헤더 설정
            },
          });

이 코드를 통해서 이미지를 백엔드 서버로 보내주고 url을 받아준다.

handlers: {
          // 이미지 처리는 우리가 직접 imageHandler라는 함수로 처리할 것이다.
          image: imageHandler,
        },

이 코드를 react-quill 라이브러리를 사용할때 필요한 modules 안에 넣어주어야되고, useMemo() 를 사용하여 랜더링 문제를 해결해 주어야 한다.
이미지 처리 방식은 벨로그에 많이 나와있으므로 이정도까지 하겠다.

return (
    <div>
      <ReactQuill
        ref={quillRef}
        modules={modules}
        formats={formats}
        placeholder="여러분의 경험을 자유롭게 적어주세요."
        className="h-[1000px] outline-none"
        theme="snow"
        value={value}
        onChange={setValue}
      />
      {/* <div>{value}</div> */}
      <div dangerouslySetInnerHTML={{ __html: value }} />
      {/* Display the 'value' state */}
    </div>
  );

또한 백엔드에 post내용을 전달해줄때

<div dangerouslySetInnerHTML={{ __html: value }} />

이 코드가 꼭 필요한데 그 이유로는

dangerouslySetInnerHTML은 브라우저 DOM에서 innerHTML을 사용하기 위한 React의 대체 방법입니다. 일반적으로 코드에서 HTML을 설정하는 것은 사이트 간 스크립팅 공격에 쉽게 노출될 수 있기 때문에 위험합니다. 따라서 React에서 직접 HTML을 설정할 수는 있지만, 위험하다는 것을 상기시키기 위해 dangerouslySetInnerHTML을 작성하고 __html 키로 객체를 전달해야 합니다.

라고 공식문서에 잘 나와 있다.

profile
초보개발자입니당
post-custom-banner

0개의 댓글