#はじめに
Draft.jsでリッチテキストエディタを実装した際に、convertFromHTMLを使うとInline Stylesが消えてしまうので、その対処法を書こうと思います。
#解決したい問題
今回作りたいのは、以下のdemoような文字色変更を実現するリッチテキストエディタです。
https://codepen.io/Kiwka/pen/oBpVve
###やりたいこと:
- リッチテキストエディタで編集後、ContentStateを(draft-js-import-htmlのstateToHTMLを用いて)HTMLに変換してデータベースに保存し、サイト上でrender。
- もう一度編集する際は、データベースからHTMLコードを取得し、ContentStateを復元。
####上手く行かなかったこと:
stateToHTMLを用いてHTMLに変換するのは上手くいったが、
そのHTMLを再びContentStateに復元する際に、Inline Stylesが消えてしまう。
以下のissueと似た状況です:
https://github.com/facebook/draft-js/issues/623
https://github.com/facebook/draft-js/issues/418
###例:
リッチテキストエディタでこのようにテキストを編集したとします。
まずはstateToHTMLを用いてHTMLに変換します。
optionsについてはこちらに書かれています。
output() {
let options = {
inlineStyles: {
red: { style: { color: 'red' } },
orange: { style: { color: 'orange' } },
yellow: { style: { color: 'yellow' } },
green: { style: { color: 'green' } },
blue: { style: { color: 'blue' } },
indigo: { style: { color: 'indigo' } },
violet: { style: { color: 'violet' } },
},
};
const html = stateToHTML(
this.state.editorState.getCurrentContent(),
options,
);
return html;
}
return結果:
<p>Te<span style="color:red">xt</span></p>
上手くいってますね!
しかし、このHTMLをContentStateに復元するのがとても厄介でした。
Draft.js公式のconvertFromHTMLを用いても、draft-js-import-htmlを用いても
復元されたContentStateは(HTMLで表すと):
<p>Text</p>
で、style属性が消えてしまいます。
なので、
HTMLをデータベースに保存しても、それを再びContentStateに復元することができません...
#対処法
convertToRaw / convertFromRaw / stateToHTMLを組み合わせたら上手く行きました。
下図のように、データベースにJSON形式のraw stateを保存することで、
HTMLにも変換できますし、contentStateもしっかり復元されます。
###例:
まずはcontentStateをraw stateに変換して
const rawState = JSON.stringify(
convertToRaw(this.state.editorState.getCurrentContent()),
);
このrawStateをデータベースに保存します。(JSON.stringifyしないとエラーが出ます)
ContentStateに復元したい場合:
データベースからrawStateを取得して、
componentWillMount() {
const contentState = convertFromRaw(JSON.parse(rawState));
this.setState = {
editorState: EditorState.createWithContent(contentState),
};
}
HTMLに変換したい場合:
データベースからrawStateを取得して、
output() {
const contentState = convertFromRaw(JSON.parse(rawState));
let options = ...//先ほどと同じなので省略
const html = stateToHTML(
contentState,
options,
);
return html;
}
これで上手くいくはずです!
#終わりに
Draft.jsに関する日本語の記事が少なかったので、今回Qiita初投稿してみました。
Reactを勉強し始めてまだ4ヶ月なので、理解が不十分でもしかしたらめちゃくちゃ勘違いしてるかもです...
もし間違いがあったり、もっと良い方法があったらぜひTwitter(@nkmt_acm)などで教えてください!