청첩장 대표사진을 첨부하고 소개말을 쓰는 부분에서 사용자가 자유롭게 글꼴, 텍스트 굵기 등을 설정하면 좋을 것 같다고 이야기를 나누었다.
텍스트에디터를 사용하여 꾸미기 요소를 처리하고 사용자가 꾸미기를 완료한 요소들을 DB에 저장하여 렌더링 해주는 것까지 기록해보려고 한다.
<와이어프레임>
여러가지 텍스트 에디터 라이브러리 중 가장 다운로드 숫자가 많았던
Quill Editor를 사용하기로 결정했다. 지원하는 것들이 많았고 다운로드 숫자가 많은 만큼 정보가 많아 구현하기에 용이할 것 같았다.
npm i react-quill
pnpm add quill react-quill
기본 템플릿 불러오는 방법
import React, { useState } from 'react';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
const TextEditor = () => {
const [value, setValue] = useState('');
const handleChange = (content: string) => {
setValue(content);
};
return (
<div>
<ReactQuill
value={value}
onChange={handleChange}
theme='snow'
/>
</div>
);
};
export default TextEditor;
우리는 모바일 퍼스트로 개발을 하고 있어서 가독성 부분에서 기본 기능들을 다 사용하기보다는 커스텀을 하면 좋을 것 같아 커스텀을 하기 위한 코드를 작성해주었다.
const modules = {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline', 'strike'],
[{ color: [] }],
[{ background: [] }],
[{ align: [] }],
],
};
return (
<div>
<ReactQuill
value={value}
onChange={handleChange}
theme='snow'
modules={modules}
/>
</div>
);
};
export default TextEditor;
유저가 정보를 입력하고 수정한 값들을 Supabase에 저장하고 미리보기에 보여주어야 하기에 react-hook-form을 사용하여 값을 저장해주었다.그리고 TextEditor를 다른 컴포넌트에서도 사용할 수 있게끔 props값을 설정해주어 재사용성이 가능한 컴포넌트로 만들어주었다.
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
interface TextEditorProps {
value: string;
onChange: (value: string) => void;
}
const TextEditor = ({ value, onChange }: TextEditorProps) => {
const modules = {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline', 'strike'],
[{ color: [] }],
[{ background: [] }],
[{ align: [] }],
],
};
return (
<div>
<ReactQuill
value={value}
onChange={onChange}
theme='snow'
modules={modules}
/>
</div>
);
};
export default TextEditor;
<TextEditor
placeholder='메인화면 문구를 설정해주세요'
value={introduceContent || ''}
onChange={(value) => setValue('mainPhotoInfo.introduceContent', value)}
/>
</div>
//TextEditor.tsx
import dynamic from 'next/dynamic';
import 'react-quill/dist/quill.snow.css';
import React from 'react';
interface TextEditorProps {
value: string;
onChange: (value: string) => void;
placeholder: string;
}
const ReactQuill = dynamic(() => import('react-quill'), { ssr: false });
const TextEditor = ({ value, onChange, placeholder }: TextEditorProps) => {
const modules = {
toolbar: [['bold', 'italic', 'underline', { color: [] }, { background: [] }]],
};
return (
<div>
<ReactQuill
placeholder={placeholder}
value={value || ''}
onChange={onChange}
theme='snow'
modules={modules}
className='custom-quill-editor'
/>
</div>
);
};
export default TextEditor;
만약 사용자가 Quill 에디터에서 다음과 같은 스타일을 적용한 텍스트를 입력했다면:
<p><strong>굵게</strong></p>
<p><em>이탤릭체</em></p>
<p><u>밑줄</u></p>
<p style="color: #ff0000;">색상 변경</p>
이런 값이 저장되게 된다.
dangerouslySetInnerHTML
속성을 사용하여 HTML를 렌더링해야한다. const mainPhotoInfo = useWatch({
control,
name: 'mainPhotoInfo',
});
// daungerouslySetInnerHTML속성을 이용하여 적용된 값 실시간으로 불러오기
<div
className='quill-preview'
dangerouslySetInnerHTML={{
__html: mainPhotoInfo?.introduceContent || '대표문구를 작성해주세요',
}}