React-Quill 사용하기(1)

스탁벅스·2023년 5월 31일
5

react-quilll

목록 보기
1/2
post-thumbnail

0. WYSIWYG 란?

WYSIWYG란, 'What you see is what you get'의 약자로, 말 그대로, 사용자가 작성하여 보여지는 것 그대로 최종 산출물로 나타나는 유저 인터페이스를 말한다. WYSIWYG 에디터는 편집화면에서 입력한 글자, 그림 등의 컨텐츠 모양 그대로 최종산물이 화면상에서, 또는 출력물에서 나타나도록 하는 에디터이다.
프로젝트를 진행중에 사용자가 블로그처럼 글씨 크기를 조절하거나 이미지를 업로드를 하는 등, 원하는 양식대로 자유롭게 게시글을 작성할 수 있게 하는 에디터를 만들어야 했다. 그래서 여러가지 방법을 찾아보다가 React-Quill이라는 라이브러리로 구현하기로 했다.

https://www.npmjs.com/package/react-quill
https://quilljs.com/docs/api/

1. React-Quill 적용하기

1. 설치

npm install react-quill

2. 가져오기

💻 코드

import ReactQuill from "react-quill";
function Write() {
  return (
    <>
      <ReactQuill />
    </>
  );
}
export default Write;

index.html

	...
<link
    rel="stylesheet"
    href="https://unpkg.com/react-quill@1.3.3/dist/quill.snow.css"
  />
	...

간단하게 import문으로 설치한 ReactQuill 컴포넌트를 가져와서 넣어주면 된다.
또한, index.html에서 저렇게 css를 위한 링크를 달아줘야 에디터가 제대로 보여진다.

📠 출력

3. 설정

React Quill의 장점은 에디터를 입맛대로 설정할 수 있다는 것이다.
건드릴 수 있는 설정들이 많은데, 자세한 건 Quill 공식문서를 보면 된다.
modules라는 객체를 만들어서 이곳에 원하는 설정들을 하면 되는데, 나는 이미지를 추가 가능하게끔 하고 싶어서 container에 image를 추가했고, 기타 글씨 관련 설정들을 해주었다. 만든 modules 객체를 컴포넌트의 modules props에 넣어주면 된다.
추가로 style props로 에디터의 크기도 조절했다.

💻 코드
Write.jsx

import ReactQuill from "react-quill";
function Write() {
 const modules = {
   toolbar: {
     container: [
       ["image"],
       [{ header: [1, 2, 3, 4, 5, false] }],
       ["bold", "underline"],
     ],
   },
 };
 return (
   <>
     <ReactQuill
       style={{ width: "800px", height: "600px" }}
       modules={modules}
     />
   </>
 );
}
export default Write;

📠 출력

에디터 상단에 이미지를 추가할 수 있는 버튼이 생겼고, 설정한대로 글씨를 변경할 수 있게 되었다.

4. 내용 작성

💻 코드

import ReactQuill from "react-quill";
import { useState } from "react";
import { createPost } from "./api/api";
function Write() {
const modules = {
 toolbar: {
   container: [
     ["image"],
     [{ header: [1, 2, 3, 4, 5, false] }],
     ["bold", "underline"],
   ],
 },
};
const [content, setContent] = useState("");
console.log(content);
const [title, setTitle] = useState("");
const handleTitleChange = (e) => {
 setTitle(e.currentTarget.value);
};
const handleSubmit = async () => {
 const date = new Date();
 try {
   await createPost({
     title: title,
     content,
     date,
   }).then((res) => console.log(res));
 } catch (error) {
   console.log(error);
 }
};
return (
 <>
   <div>
     <label htmlFor="title">제목</label>
     <input id="title" type="text" onChange={handleTitleChange} />
     <ReactQuill
       style={{ width: "800px", height: "600px" }}
       modules={modules}
       onChange={setContent}
     />
   </div>
   <button style={{ marginTop: "50px" }} onClick={handleSubmit}>
     제출
   </button>
 </>
);
}
export default Write;

content라는 state를 선언하고 ReactQuill 컴포넌트에 onChange props를 활용해서 content의 값을 바꾸고 이 값을 콘솔창에 찍어보았다.

추가로, 에디터 밑에 제출 버튼을 만들어서 클릭시 작성한 내용이 미리 만든 서버에 전송되게끔 하였다.

📠 출력

눈에 띄는 특징이 content의 값이 단순히 내용만 출력되는 게 아니라, 이 내용이 html형식으로 출력된다는 것이다. 즉, 여기서 작성한 내용이 html형식의 string으로 저장되고, 나중에 여기서 작성한 내용을 불러올때는 이 string을 html로 파싱해서 DOM에 추가하는 방식으로 불러오면 된다.

5. 작성 내용 불러오기

💻 코드

import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
import { getPost, IPost } from "./api/api";
import * as DOMPurify from "dompurify";
import PostTitle from "./PostTitle";
function Post() {
const { id } = useParams();
const [data, setData] = useState<IPost>({});
useEffect(() => {
 getPost(id + "").then((res) => setData(res));
}, []);
return (
 <div>
   <PostTitle title={data?.title} />
   {data?.content && (
     <div
       style={{
         width: "60vw",
         whiteSpace: "normal",
       }}
       dangerouslySetInnerHTML={{
         __html: DOMPurify.sanitize(String(data?.content)),
       }}
     />
   )}
 </div>
);
}
export default Post;

리액트에서는 기본적으로 div나 span태그에 dangerouslySetInnerHTML이라는 속성이 있다. 말그대로 '위험하게 내부에 HTML 추가하기'라는 뜻인데 이게 왜 위험하냐면 DOM에 HTML을 추가할때 사이트간 스크립팅 공격(XSS)에 취약하기 때문이다. 이로 인해 관리자가 아닌 악성 유저가 페이지에 악성 스크립트를 삽입하는 등 비정상적인 기능을 수행할 수 있다. 이에 대한 해결방안으로 DOMPurify라는 HTML을 sanitize 해주는 라이브러리를 활용했다.
https://github.com/cure53/DOMPurify

📠 출력

작성한 내용이 무사히 잘 출력된다.

3. 이미지 문제


위에 작성한 내용의 문자열이다. 보다시피 react-quill 라이브러리에서 기본적으로 이미지는 base64로 인코딩되어서 img 태그의 src 속성에 삽입되기 때문에 나는 짧은 글을 작성했지만, 이미지 때문에 내용이 어마어마하게 길어진다. 따라서 이 이미지를 s3와 cloudfront를 이용해서 클라우드 서버 url을 통해 이미지를 불러오도록 고쳐보겠다.

profile
환영합니다. 스탁벅스입니다.

0개의 댓글