본문 바로가기
SPA/Next

[Next] Editor 사용하기 (3) - React Draft Wysiwyg

by J4J 2022. 1. 9.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 React Draft Wysiwyg Editor 사용하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

들어가기에 앞서 다음 글도 참고해보시면 좋을 것 같습니다.

 

 

 

 

앞선 글들에서 언급했듯이 Next에서 Editor를 사용해보기 위해 다음과 같은 총 3개의 패키지를 확인할 수 있었습니다.

 

  • react-quill
  • @toast-ui/react-editor
  • react-draft-wysiwyg

 

 

 

이번엔 개인 순위로 3등으로 생각했던 react-draft-wysiwyg에 대해 소개를 해보겠습니다.

 

구현 방법과 간단한 특징들에 대해 적어보겠습니다.

 

 

반응형

 

 

이미지 서버 설정

 

구현하기 전 이미지 서버 설정이 필요합니다.

 

서버 설정과 관련된 것은 위의 React Quill을 참고해주시면 될 것 같습니다.

 

 

 

 

React Draft Wysiwyg 사용 방법

 

[ 1. 패키지 설치 ]

 

$ npm install react-draft-wysiwyg draft-js draftjs-to-html html-to-draftjs
$ npm install -D @types/react-draft-wysiwyg @types/draft-js @types/draftjs-to-html @types/html-to-draftjs

 

 

 

[ 2. Editor 컴포넌트 생성 ]

 

/components 위치에 editor.tsx파일을 생성하여 다음과 같이 Editor를 만들어보겠습니다.

 

import { NextPage } from 'next';
import * as React from 'react';
import axios from 'axios';

import { Editor as WysiwygEditor } from 'react-draft-wysiwyg';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import { ContentState, convertToRaw, EditorState } from 'draft-js';
import draftToHtml from 'draftjs-to-html';
import htmlToDraft from 'html-to-draftjs';

interface IEditor {
    htmlStr: string;
    setHtmlStr: React.Dispatch<React.SetStateAction<string>>;
}

const Editor: NextPage<IEditor> = ({ htmlStr, setHtmlStr }) => {

    const [editorState, setEditorState] = React.useState(EditorState.createEmpty());

    React.useEffect(() => {
        const blocksFromHtml = htmlToDraft(htmlStr);
        if (blocksFromHtml) {
            const { contentBlocks, entityMap } = blocksFromHtml;
            const contentState = ContentState.createFromBlockArray(contentBlocks, entityMap);
            const editorState = EditorState.createWithContent(contentState);
            setEditorState(editorState);
        }
    }, [])

    // editor 수정 이벤트
    const onEditorStateChange = (editorState: EditorState) => {
        setEditorState(editorState);
        setHtmlStr(draftToHtml(convertToRaw(editorState.getCurrentContent())));
    };

    const uploadCallback = (file: Blob) => {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
    
            reader.onloadend = async () => {
                const formData = new FormData();
                formData.append("multipartFiles", file);
                const res = await axios.post('http://localhost:8080/uploadImage', formData);
    
                resolve({ data: { link: res.data } });
            };
    
            reader.readAsDataURL(file);
        });
    };

    // toolbar 설정
    const toolbar = {
        list: { inDropdown: true }, // list 드롭다운
        textAlign: { inDropdown: true }, // align 드롭다운
        link: { inDropdown: true }, // link 드롭다운
        history: { inDropdown: false }, // history 드롭다운
        image: { uploadCallback: uploadCallback }, // 이미지 커스텀 업로드
    }

    // 언어 설정
    const localization = {
        locale: 'ko',
    }

    return (
        <WysiwygEditor
            editorClassName="editor" // Editor 적용 클래스
            toolbarClassName="toolbar" // Toolbar 적용 클래스
            toolbar={toolbar} 
            placeholder="내용을 입력하세요."
            localization={localization}
            editorState={editorState}
            onEditorStateChange={onEditorStateChange}
        />
    )
}

export default Editor;

 

 

 

 

[ 3. Editor 사용하는 파일 작성 ]

 

위에 만들어 둔 Editor 컴포넌트를 index.tsx에서 불러와 사용해보겠습니다.

 

작성하기 전 확인해야 될 부분은 Editor 컴포넌트를 불러올 때 dynamic을 이용하여 ssr을 false로 설정해줘야 합니다.

 

설정하지 않을 경우 정상 동작되지 않습니다.

 

import * as React from 'react';
import dynamic from 'next/dynamic';
import styled from 'styled-components';
import { NextPage } from 'next';

const Editor = dynamic(() => import('../components/editor'), { ssr: false }); // client 사이드에서만 동작되기 때문에 ssr false로 설정

const Index: NextPage = () => {
    // state
    const [htmlStr, setHtmlStr] = React.useState<string>('');

    // ref
    const viewContainerRef = React.useRef<HTMLDivElement>(null);

    // useEffect
    React.useEffect(() => {
        if(viewContainerRef.current) {
            viewContainerRef.current.innerHTML = '<h2>html 코드를 이용하여 만들어지는 View입니다.</h2>'
            viewContainerRef.current.innerHTML += htmlStr;
        }
    }, [htmlStr])

    return (
        <>
            <EditorContainer>
                <Editor htmlStr={htmlStr} setHtmlStr={setHtmlStr} />
            </EditorContainer>

            <Contents.Container>
                <Contents.HtmlContainer>
                    <h2>Editor를 통해 만들어진 html 코드입니다.</h2>
                    {htmlStr}
                </Contents.HtmlContainer>

                <Contents.ViewContainer ref={viewContainerRef} />
            </Contents.Container>
        </>
    );
};

export default Index;

// style
const EditorContainer = styled.div`
    width: 800px;
    height: 400px;

    margin: 0 auto;

    // Editor 스타일 설정
    .wrapper { }

    .editor {
        height: 300px;
    }

    .toolbar { }
`;

const Contents = {
    Container: styled.div`
        width: 1200px;
        
        margin: 0 auto;

        display: flex;
        gap: 40px;

        & > div {
            width: 600px;

            padding: 16px;

            box-sizing: border-box;

            line-break: anywhere;
        }
    `,

    HtmlContainer: styled.div`
        border: 2px solid orange;
    `,

    ViewContainer: styled.div`
        border: 2px solid olive;
    `,
}

 

 

 

 

테스트

 

코드를 위와 같이 작성하고 실행을 해보면 다음과 같은 결과를 확인할 수 있습니다.

 

실행 결과

 

 

 

상위는 Editor, 좌측은 Editor에 의해 만들어지는 html, 우측은 만들어진 html을 이용하여 화면을 구성할 때 나오는 화면입니다.

 

 

 

 

특징

 

Editor를 찾아보기 전에 원하는 Editor 기능들은 다음과 같습니다.

 

  • 텍스트 정렬
  • 텍스트 색깔 지정
  • 이미지 업로드
  • 이미지 사이즈 조절
  • XSS 방지
  • 기타 등등...

 

 

 

React Draft Wysiwyg에서는 위의 기능들을 대부분 지원했습니다.

 

하지만 다음과 같이 아쉬웠던 부분이 많이 보였습니다.

 

  • 이미지 가운데 정렬 정상 동작 불가
  • 한글 입력 시 onEditorStateChange 이벤트 발생하지 않음
  • style을 class로 적용되지 않고 style로 적용
  • 복잡하진 않지만 사용성이 다른 것들에 비해 간단하지 않음

 

 

 

이런 특징들을 확인할 수가 있었고 다른 것들에 비해 크게 눈에 띄는 장점들은 없었던 것 같습니다.

 

그래서 사용해본 Editor 중에는 가장 마지막 순위로 생각하게 되었고 Editor을 하나 선택해서 사용할 때는 개인적으로 React Draft Wysiwyg는 배제하고 다른 Editor를 생각할 것 같습니다.

 

 

 
 

 

 

 

이상으로 React Draft Wysiwyg Editor 사용하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글