커뮤니티를 만들다보니 Text Editor가 필요해 몇 에디터를 비교해봤다.
무엇보다 사용성에 초점을 두어 내가 사용하기 편한 에디터를 찾게 되었는데,
다름아닌 Toast UI Editor를 선택하게 되었다.
Toast UI Editor는 리액트, 뷰, Vanilla JS를 지원하는 에디터로 Markdown 에디터임에도,
WYSIWYG 에디터를 동시에 지원한다는 장점이 있다.
또, 마크다운의 프리뷰와 기본 뷰어도 제공해 개발에도, 사용에도 용이하다고 판단했다.
에디터를 typescirpt와 yarn berry를 이용한 리액트에 적용하는 방법은 아래를 통해 알아보자.
yarn add @toast-ui/editor @toast-ui/react-editor
yarn
명령어를 통해 설정을 업데이트 해준다.packageExtensions:
'@toast-ui/editor@*':
dependencies:
prosemirror-transform: '*'
import '@toast-ui/editor/dist/toastui-editor.css';
import { Editor } from '@toast-ui/react-editor';
import { useRef } from 'react';
cosnt Editor = () => {
const editorRef = useRef();
return (
<>
<Editor
previewStyle="vertical"
height="400px"
initialEditType="markdown"
initialValue="hello"
ref={editorRef}
/>
</>
);
}
위의 예시처럼 Editor를 사용할 수는 있지만, 일반적으로 페이지 컴포넌트에 에디터를 가져다
집어넣지는 않기에 에디터를 자식 컴포넌트로 두어 페이지에서 다루는 과정을 진행해보았다.
아래의 코드를 참고하자.
import { MutableRefObject } from 'react';
import '@toast-ui/editor/dist/toastui-editor.css';
import { Editor } from '@toast-ui/react-editor';
interface Props {
editorRef: MutableRefObject<unknown>
}
const PostEditor: React.FC<Props> = ( props: Props ) => {
return (
<>
<Editor
height="100%"
initialEditType="wysiwyg"
useCommandShortcut={true}
ref={(element) => {
props.editorRef.current = element;
}}
/>
</>
);
};
export default PostEditor;
import { useRef, useState } from 'react';
import PostEditor from '../../components/PostEditor/PostEditor';
const NewPostPage = (): JSX.Element => {
const editorRef = useRef<any>(null);
const [title, setTitle] = useState('');
function PostSubmitHandler() {
if(isValidContent()){
const INSTANCE = editorRef.current?.getInstance();
if(INSTANCE.mode==='wysiwyg'){
const CONTENT = INSTANCE.getHTML();
submitPost(title, CONTENT);
}else if(INSTANCE.mode==='markdown'){
const CONTENT = INSTANCE.getMarkdown();
submitPost(title, CONTENT);
}
}
}
function isValidContent() {
if(title===''){
alert('제목을 입력해주세요.');
return false;
}else if(editorRef.current?.getInstance().getMarkdown()===''){
alert('내용을 입력해주세요.');
return false;
}
return true;
}
function submitPost(title: string, content: string) {
console.log(title, content);
//통신
}
return (
<>
<input type='text' placeholder='제목을 입력해주세요.' onChange={(e)=>{setTitle(e.target.value);}}/>
<PostEditor editorRef={editorRef} />
<button onClick={PostSubmitHandler}>등록</button>
</>
);
};
export default NewPostPage;
간단하게 에디터 컴포넌트와 페이지 컴포넌트를 나누어
제목, 내용을 받아 버튼으로 처리할 수 있도록 작성했다.
에디터에 설정값들을 미리 고정시켜두었지만, 에디터의 설정들은 변경이 가능하다.
따라서 작성한 에디터 컴포넌트에 props를 통해 Toast Editor 컴포넌트에 넘겨주는 방식으로
페이지 컴포넌트에서 설정할 수 있게 만드는게 더 나은 코드일 것이다.
뷰어는 Editor보다 훨씬 더 쉽게 사용이 가능하다.
아래의 코드를 통해 확인할 수 있다.
import { Viewer } from '@toast-ui/react-editor';
import '@toast-ui/editor/dist/toastui-editor-viewer.css';
interface Props {
content: string
}
const PostViewer: React.FC<Props> = ( props: Props ) => {
return(
<>
<Viewer initialValue={props.content} />
</>
);
};
export default PostViewer;
위처럼 간단히 사용할 수 있고 만약 뷰어 내부의 스타일을 적용하고 싶다면
div로 감싸져있는 형태로 존재하기에 아래처럼 적용해줄 수 있다.
Emotion.js를 사용한 예시지만 css를 주목해주길 바란다.
import { Viewer } from '@toast-ui/react-editor';
import { css } from '@emotion/react';
import '@toast-ui/editor/dist/toastui-editor-viewer.css';
interface Props {
content: string
}
const PostViewer: React.FC<Props> = ( props: Props ) => {
return(
<div css={PostViewerStyle}>
<Viewer initialValue={props.content} />
</div>
);
};
const PostViewerStyle = css`
div{
font-size: 16px;
font-weight: 600;
}
`;
export default PostViewer;
이렇게 간단히 Toast UI Editor를 React에 적용하는 방법을 알아봤다.
생각보다 간단하지만, 컴포넌트를 구성하는 방식은 다양하게 나올 수 있다.
어떤 코드가 더 좋은 코드인지를 생각해 개발해야 한다는 생각을 간단한 적용에서도 찾을 수 있어
조금 복잡한 심정을 갖게 했다.
다음에도 프로젝트 진행에 문제가 됐던 사항이 있다면 또 기록하며 생각해봐야겠다.
Toast UI도 결국 ProseMirror 쓰더라구요