以下是我測試的環境
node:v15.12.0
幾個套件的版本:
"draft-js": "^0.11.7",
"next": "11.1.2",
"react": "17.0.2"
最近在嘗試為NextJS 加入一個rich text editor,或者可會叫WYSIWYG (what you see is what you get),中文有人稱之為「即見即所得」的網頁上給用戶發表內容時所用的編輯器,正如wordpress、討論區等等都會用到
在ReactJS 及NextJS 中較多人推薦的有DraftJS , Quill, Slate 這3個,原來早已不是ckeditor和tinymce之爭了......
DraftJS vs Quill vs Slate
3個以下載量而論slate被我放棄了,因為網上找了很多討論,相對比較少,因為下載量=使用人數=遇到各類問題的機會,我一直深信當我遇到這問題時,世上另一角落都有人遇上,所以一套package足夠多人用,當我遇上問題時就較早解決,所以我放棄了slate
然後是quill vs draftJS,我選擇了draftJS
原因一 :draftJS update比quill 較密
原因二:draftJS 是facebook出的
原因三:當時學react-native 時被編輯器所困,當時發現很多人也是推薦用draftJS,所以為了react-native跟web app 用戶能有更近接的體驗
原因四:draftJS比quill 更「裸」 quill 官方在demo的文件中還有些toolbar 給你,但draftJS更少,draftJS給我的感覺就是個textarea,反正一定有超多東西要搞的,不如由0開始?! 所以最終選擇了draftJS
題外話補充:有很多人推薦用react-draft-wysiwyg,是其他人將draftJS整理得沒有那麼「裸」,功能較完整的版本,但我發現更新不夠密集,以及對nextJS支援也會有些少問題,所以放棄沒有用,因為原生的draftJS是有插件包的,當然如果你不是用NextJS單純用ReactJS建議你可以去了解一下這個懶人包draftJS
draftJS 在 ReactJS 上運作還是遇上的問題較少,但在NextJS 上則遇上更多問題,主要卡在以下
1. SSR問題,選擇了NextJS不就是為了SSR嗎?但draftJS會因為SSR而發生錯誤!
比如官方文檔是教你
const [editorState, setEditorState] =useState(()=>EditorState.createEmpty());
但這樣會報錯的官方的issue#1199 不能用createEmpty(), 而是建立一個emptyContentState 並用另一個functioncreateWithContent()
來解決
你大致應該這樣寫
const [editorState, setEditorState] = useState(EditorState.createWithContent(emptyContentState));
const emptyContentState = convertFromRaw({
entityMap: {},
blocks: [
{
text: '',
key: 'foo',
type: 'unstyled',
entityRanges: [],
},
],
});
2. 當解決了上面的問題,你終於可以在一個空白的Textarea 上打字而不收到錯誤提示了!但你在console.log 中會看到另一個報錯
Warning: Prop `data-editor` did not match. Server: "6ap7k" Client: "dooth"
後來發現是 data-editor
這個prop的問題,原來這問題在2016年時已經有人提了官方不如修正此問題來方便SSR #796 最終在很多不同的issues中被我找到了較多人提及的一點 #385 原來又是SSR問題?!
簡言之,就是類似isLoading 常見的做法,做給draftJS就ok了
const [editor, setEditor] = useState(false);
useEffect(() => {
setEditor(true);
}, [editorState]);
return (
<div className="App">
{editor ? (
<Editor />
) : null}
</div>
)
3. 官方教學也不是functional component?這個我也不知是否算問題?
NextJS 官方demo或者一些教學都已全面是functional component 以及用 React Hooks 來做了,但 draftJS 雖然有大量的demo 或是都是 class component,對於近年剛剛接觸React的人,是完全依賴React Hooks,所以在初期試用demo時會經常改漏了`this.xxx`
全部代碼
(注:這只是一個純空白頁面,只當DraftJS +NextJS init setting)
import { Editor, EditorState, convertFromRaw } from 'draft-js';
import { useEffect, useState } from 'react';
function App() {
const [editorState, setEditorState] = useState(
EditorState.createWithContent(emptyContentState)
);
const [editor, seteditor] = useState(false);
console.log();
useEffect(() => {
seteditor(true);
}, [editorState]);
return (
<div>
<div className="App">
{editor ? (
<Editor editorState={editorState} onChange={setEditorState} />
) : null}
</div>
</div>
);
}
const emptyContentState = convertFromRaw({
entityMap: {},
blocks: [
{
text: '',
key: 'foo',
type: 'unstyled',
entityRanges: [],
},
],
});
export default App;
近期留言