너와 나의 프로그래밍

Development Etc. - React-Quill(Quill) for Typescript + Next.js 본문

Etc./Development Etc.

Development Etc. - React-Quill(Quill) for Typescript + Next.js

Whatever App's 2023. 6. 14. 00:25

 

 

 

아마 대표적으로 유명한 Javascript Library Web Editor로 유명한 Quill은 Web에서 많이 봤을법한 텍스트 에디터다.

WYSIWYG이라는 에디터로도 불리는데 WYSIWYG은 What You See Is What You Get, "보는 대로 얻는다"라는 문서 편집 과정에서 화면에 포맷된 낱말, 문장이 출력물과 동일하게 나오는 방식이라고 한다.

 

많은 라이브러리를 사용해본적은 없지만 그래도 항상 내 Needs에 맞는 텍스트 에디터 라이브러리는 Quill이였다. 그 중에 React나 Next.js에서도 접목시킬 수 있는 React-Quill이라는 Quill 기반 라이브러리까지 있어서 개발하기도 쉬워졌다.

 

특히 이 라이브러리는 Quill - Your powerful rich text editor (quilljs.com) 이곳의 "PLAYGROUND" 탭에서 자신에게 맞는 조건을 입력해서 미리 경험할 수 있는 환경도 제공해줘서 미리 체험하고 사용할 수 있다는 점에서도 좋았다.

(물론 요즘 라이브러리들이 거의 다 이런걸 지원하지만...)

 

이번에는 기본적인 Quill의 사용법 보다는 React-Quill 라이브러리의 사용법과 React대신에 Next.js + Typescript 환경에서 어떻게 개발해야 되는지 설명하려고 한다.

 

Next.js의 초기세팅은 되어있다고 판단하고 React-Quill 라이브러리 설치부터 해주자.

// npm
npm i react-quill
// yarn
yarn add react-quill

 

※ 타입스크립트의 대한 @types 라이브러리가 있는지 찾아보았지만 딱히 Type의 대한 라이브러리는 없었다.

 

import { useRef, useMemo, MutableRefObject } from "react";
import dynamic from "next/dynamic";
import styled from "styled-components";
import "react-quill/dist/quill.snow.css";
import ReactQuill, { ReactQuillProps } from "react-quill";

interface IWrappedComponent extends ReactQuillProps {
	forwardedRef: MutableRefObject<ReactQuill>;
}

const Quill = dynamic(
	async () => {
		const { default: RQ } = await import("react-quill");

		const QuillJS = ({ forwardedRef, ...props }: IWrappedComponent) => (
			<RQ ref={forwardedRef} {...props} />
		);
		return QuillJS;
	},
	{ ssr: false }
);

const Container = styled.div`
	width: 100%;
	height: 100%;
`;

const CustomQuill = styled(Quill)`
	.ql-toolbar {
		border: 0.1rem solid #eeeeee;
		border-radius: 0.8rem 0.8rem 0 0;
	}

	.ql-container {
		height: 50rem;
		border: 0.1rem solid #eeeeee;
		border-radius: 0 0 0.8rem 0.8rem;
	}
`;

const Editor = ({
	value,
	onChange,
}: {
	value: string;
	onChange: (e: string) => void;
}) => {
	const quillRef = useRef<ReactQuill>(null);

	const modules = useMemo(
		() => ({
			toolbar: {
				container: [
					[{ header: [1, 2, 3, 4, 5, 6, false] }],
					[{ size: [] }],
					["bold", "italic", "underline", "strike", "blockquote"],
					[{ list: "ordered" }, { list: "bullet" }, { align: [] }],
					["image"],
				],
			},
			clipboard: {
				matchVisual: false,
			},
		}),
		[]
	);

	return (
		<Container>
			<CustomQuill
				forwardedRef={quillRef}
				value={value}
				onChange={onChange}
				placeholder="내용을 입력하세요…"
				modules={modules}
			/>
		</Container>
	);
};

export default Editor;

 

React-Quill 라이브러리를 사용하면서 다양한 블로그에서 참고도 많이 하면서 어떻게 하면 타입스크립트를 완벽하게 적용할 수 있을지 정말 고민도 많이 했다.

 

위 modules는 Quill에서 사용하는 방식으로 텍스트 에디터에서 어떤 동작을 하는 버튼을 사용하는지의 대해 Josn 형식으로 선언을 해준다.

 

예를들어 글의 텍스트 사이즈를 어떻게 할 것인지, 글의 스타일, 리스트 스타일 등등 에디터에서 사용하는 다양한 기능을 제공해준다.

 

그리고 설명을 조금 붙이자면 제일 까다로웠던 타입스크립트 부분인데 이번에 에디터를 사용하면서 가장 어려웠던 부분이 useRef를 사용하는 부분과 Next.js에서 dynamic을 활용해서 react-quill을 import 해서 컴포넌트화 시키는 부분이였다. 

(useRef는 에디터에 이미지를 업로드 할 때 API 통신을 위해 DOM 제어를 위해 사용했었는데 위 코드에서는 이미지 업로드의 대한 코드는 제외했다. 마지막에 깃허브 주소 참조하겠습니다!)

 

예전에 SSR을 지원하지 않는 라이브러리를 사용할 때는 import를 사용할 수 없는 라이브러리 같은 경우에는 next/dynamic을 사용하여 import를 해서 사용했던 적이 있었는데 이놈의 dynamic은 진짜 쓸 때마다 정말 어려운거 같다. 완벽하게 이해하기 보다는 이 안에서 어떻게 구현을 했는지 외우는게 어쩌면 더 빠르지 않을까 라는 생각이 들었다.

 

그리고 마지막으로 타입선언을 통해서 SSR에서도 작용할 수 있도록 컴포넌트화 시켜줬다.

 

요즘 타입스크립트를 안쓰는 프로젝트가 거의 없다시피해서 아마 타입스크립트를 활용해서 라이브러리에 접목시키는게 가장 어려울거 같은데 이 점을 참고해서 개발하면 좋을 것 같다!

 

 

 

 

React-Quill에서 Image Upload 코드 : Next.js-Study/next-quill-exmaple at main · soft91/Next.js-Study · GitHub

반응형