
<textarea>에서는 줄 바꿈이 되지 않고 내용에 스타일을 줄 수 없는 등의 불편함이 있다. 이런 단점을 보완하기 위해 에디터를 사용한다.
리액트의 에디터 라이브러리에는 react-draft-wysiwyg, react-quill, @toast-ui/react-editor 등이 있다.

셋 중에서 react-quill이 크게 앞서있는 것을 볼 수 있다.
yarn add react-quill
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
react-quill을 사용할 땐 전용 css 파일도 호출해야한다. 그리고 에디터를 사용할 곳에 <ReactQuill onChange={체인지핸들러} />을 입력하면 에디터를 사용할 수 있다.
여기서 사용되는 onChange는 jsx의 onChange와 전혀 다른, react-quill 개발자가 만들어놓은 커스텀 요소이다.
하지만 이렇게 진행하면 Document is not defined 에러가 뜬다. react-quill은 브라우저의 document 객체를 필요로 하는데 nextJS는 서버사이드렌더링(SSR)을 지원하는 프레임워크이기 때문에 프리렌더링 시 오류가 나는 것이다. 이 문제를 해결하려면 react-quill을 document 객체가 선언된 후에 import 해야한다.
import dynamic from 'next/dynamic';
const ReactQuill = dynamic( async() => await import('react-quill'), {
ssr : false
})
dynamic import는 단순히 이런 SSR 이슈 해결에만 도움을 주는 것이 아니라 성능 최적화에도 기여한다. 처음부터 다운로드 받아야할 필요가 없는 소스들을 후에 필요한 시점에 다운로드 받도록 해 초기 로딩속도를 높여줄 수 있다. 이렇게 코드를 분리해 필요한 시점에 import 해올 수 있도록 하는 방식을 코드 스플릿팅이라고 한다.
import { useForm } from "react-hook-form";
import "react-quill/dist/quill.snow.css";
import dynamic from "next/dynamic";
const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });
export default function WebEditorPage() {
const { register, setValue, trigger } = useForm({
mode: "onChange",
});
const handleChange = (value: string) => {
setValue("contents", value === "<p><br></p>" ? "" : value); // 공백인 경우 html 코드 삭제
trigger("contents"); // useForm의 trigger로 onChange 되었음을 react-hook-form에게 알려줌
};
return (
<div>
작성자: <input type="text" {...register("writer")} />
<br />
비밀번호: <input type="password" {...register("password")} />
<br />
제목: <input type="text" {...register("title")} />
<br />
내용: <ReactQuill onChange={handleChange} />
<br />
<button>등록하기</button>
</div>
);
}
웹 에디터로 작성한 내용은 html 태그가 포함된 문자열이기 때문에 화면에 출력할 땐 태그를 노출하지 않으면서 html 기능은 적용된 형태로 해야한다. React에서는 보안이슈로 인해 기본적으로 html 태그를 직접 삽입할 수 없게 되어있다. 하지만 dangerouslySetInnerHTML 속성을 사용하면 html 태그를 직접 넣을 수 있다. <div>와 <span>에 사용할 수 있는데, 이 땐 닫는 태그 없이 -/> 식의 빈 태그로 작성해야 한다.
dangerouslySetInnerHTML 속성을 사용하면 악의적으로 작성된 스크립트가 해당 요소 안에서 불러와질 수 있기 때문에 굉장히 위험하다. 이렇게 사이트의 취약점을 노려서 html과 javascript로 악의적 코드를 웹 브라우저에 심고 사용자 접속 시 실행되도록 하는 것을 크로스 사이트 스크립트(Cross Site Script - XSS)라고 한다.
DOMpurify라는 라이브러리로 공격 코드를 자동으로 차단해줄 수 있다.
{process.browser &&
<div
dangerouslySetInnerHTML={{
__html: Dompurify.sanitize(String(불러온 데이터))
}}
/>
}
Dompurify의 SSR 에러를 해결하기 위해 조건부로 렌더링을 해줘야한다.
Open Web Application Security Project
웹 관련 정보노출이나 악성파일 및 스크립트, 보안 취약점을 연구하고 10대 취약점을 발표하며 3-4년에 한 번씩 정기적으로 업데이트 된다.