DREAMCARD_최종프로젝트_quill editor를 사용한 커스텀 청첩장 만들기

정소현·2024년 10월 28일
0

팀프로젝트

목록 보기
29/50
post-thumbnail

청첩장 대표사진을 첨부하고 소개말을 쓰는 부분에서 사용자가 자유롭게 글꼴, 텍스트 굵기 등을 설정하면 좋을 것 같다고 이야기를 나누었다.
텍스트에디터를 사용하여 꾸미기 요소를 처리하고 사용자가 꾸미기를 완료한 요소들을 DB에 저장하여 렌더링 해주는 것까지 기록해보려고 한다.

<와이어프레임>

여러가지 텍스트 에디터 라이브러리 중 가장 다운로드 숫자가 많았던
Quill Editor를 사용하기로 결정했다. 지원하는 것들이 많았고 다운로드 숫자가 많은 만큼 정보가 많아 구현하기에 용이할 것 같았다.

https://quilljs.com/


구현방법

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;

우리는 모바일 퍼스트로 개발을 하고 있어서 가독성 부분에서 기본 기능들을 다 사용하기보다는 커스텀을 하면 좋을 것 같아 커스텀을 하기 위한 코드를 작성해주었다.

  • modules를 사용하여 바를 커스텀 해준 다음 ReactQuill에 modules를 추가하여 설정값을 적용해주었다.


  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;

🙌 quill next/dynamic으로 컴포넌트 동적으로 로드시켜 서버 사이드 렌더링 시 document객체를 사용하지 않도록 처리하기

  • next.js는 기본적으로 서버 사이드 렌더링을 지원함으로 서버로부터 웹 페이지를 렌더링하는 시점에서 document object를 선언하기 전이라 document가 선언되지 않았다는 에러가 난다.
  • import 시 dynamic을 이용하여 동적 렌더링으로 발생할 수 있는 오류를 처리해준다.

☘️ quill editor에서 설정한 정보 form형태로 저장하기

  1. useFormContext()를 사용하여 HTMl형태로 설정된 정보를 저장한다.
    나는 quill text editor를 사용하는 부분을 이후 다른 곳에 재사용 하기위해 컴포넌트로 만들었다.
  2. 부모 컴포넌트에서 onChange를 props로 내려주어 값을 저장할 수 있도록 만들었다.
    // MainPhotoInput.tsx
<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;
  1. 여기에서 setValue에 저장된 "mainPhotoInfo.introduceContent"는 onChange콜백으로 전달된 Quill에디터에 입력된 텍스트의 HTML형식이다.

만약 사용자가 Quill 에디터에서 다음과 같은 스타일을 적용한 텍스트를 입력했다면:

  • 굵게 (Bold)
  • 이탤릭체 (Italic)
  • 밑줄 (Underline)
  • 색상 변경 (Color)
<p><strong>굵게</strong></p>
<p><em>이탤릭체</em></p>
<p><u>밑줄</u></p>
<p style="color: #ff0000;">색상 변경</p>

이런 값이 저장되게 된다.

  1. Next.js 환경에서 개발중인 지금 quill 에디터로부터 저장된 HTML형식의 텍스트를 미리보기 페이지에서 표시하려면 dangerouslySetInnerHTML 속성을 사용하여 HTML를 렌더링해야한다.
  2. MainPhotoPreView.tsx에서 (미리보기 컴포넌트)
    useWatch()를 사용해 저장해두었던 값을 변동이 있을 때마다 가져오도록 한다.
 const mainPhotoInfo = useWatch({
    control,
    name: 'mainPhotoInfo',
  });

// daungerouslySetInnerHTML속성을 이용하여 적용된 값 실시간으로 불러오기

 <div
        className='quill-preview'
        dangerouslySetInnerHTML={{
          __html: mainPhotoInfo?.introduceContent || '대표문구를 작성해주세요',
        }}

0개의 댓글