LoginSignup
17
12

More than 5 years have passed since last update.

Draft.jsのデータ保存について

Posted at

概要

Reactの復習ついでに、Draft.jsを使っていたら躓いたのでメモ。

Draft.js自体はReactで作られたリッチエディタフレームワークです。(https://github.com/facebook/draft-js)

やりたいこと

  1. エディタで編集した内容をファイルに保存すること
  2. ファイルに保存したデータからエディタの状態を復元すること

Editor自体の実装は以下のようにしておきます。
Electronを使って実装をしていたので、fsでファイルの保存・読み込みを行います。

Editor.js
import React, {Component} from 'react';
import {Editor, EditorState, RichUtils} from 'draft-js';

const editorStyle = {
    height: "300px", 
    width: "300px", 
    backgroundColor: "#eeeeee", 
    textAlign: "left",
    padding: "10px",
    border: "1px solid #e0e0e0"
};

export default class EditorSample extends Component {

  editor;

  constructor(props) {
    super(props);

    this.state = {
      editorState: EditorState.createEmpty()
    };
  }

  render() {

    return(
        <div>
            <h2>EditorSample</h2>
            <div>
                <StyleButton label="H1" style="header-one" onToggle={this.onToggle}/>
            </div>
            <div onClick={this.onClick} style={editorStyle}>
            <Editor ref={(el) => {this.editor = el;}} 
                    editorState={this.state.editorState} 
                    onChange={this.onChange}/>
            </div>
            <div style={{marginTop: "10px"}}>
                <button onClick={this.save}>Save</button>
                <button onClick={this.read}>Read</button>
            </div>
        </div>
    );
  }

  onClick = () => {
    if (this.editor) {
       this.editor.focus();
    }
  };

  onChange = (editorState) => {
    this.setState({editorState});
  };

  onToggle = (style) => {
    const editorState = RichUtils.toggleBlockType(this.state.editorState, style);
    this.setState({editorState});
  };

  save = () => {
    // 実装は後述
  };
  read = () => {
    // 実装は後述
  };
}

class StyleButton extends Component {

    render() {
      return (
        <span onMouseDown={this.onToggle}>
          {this.props.label}
        </span>
      );
    }

    onToggle = (e) => {
        e.preventDefault();
        this.props.onToggle(this.props.style);
    };
}

EditorSample_normal.png
EditorSample_Block_H1.png

HTMLファイルとして保存・復元

結論から言うとうまくいきません。改行が取り除かれたりして、正確に復元できませんでした。BlockやInlineStyleなどをカスタマイズした場合を考えると頭が痛くなるやり方。

htmlとしてexport/importをしてくれるライブラリを使用しました。
https://github.com/sstur/draft-js-utils

// export 
import {stateToHTML} from 'draft-js-export-html';
import fs from 'fs';

// class内に定義
save = () => {
  const contentState = this.state.editorState.getCurrentContent();
  const content = stateToHTML(contentState);
  const filePath = "xxxxx";
    // ファイル保存処理 
    fs.writeFileSync(filePath, content, 'utf-8');
};


// import
import {stateFromHTML} from 'draft-js-import-html';
import fs from 'fs';

// class内に定義
read = () => {
  const filePath = "xxxx";
  // ファイル読み込み
  const content = fs.readFileSync(filePath, 'utf-8');

  const contentState = stateFromHTML(content);
  const editorState = EditorState.createWithContent(contentState);
  this.setState({editorState});
};

JSONとしてそのまま保存する

ファイルとして出力することを目的とせず、復元することに重きを置くのであればcontentStateをそのままファイル保存するのが良いと思いました。

Editor自体がImmutable.jsを利用しているので、そのままファイルに保存してもうまく行きません。
convertFromRawconvertToRawを使用しますが、どちらもDraft.js標準の関数です。これを使うとJSONとして適切に変換を行ってくれます。

// export 
import {convertToRaw} from 'draft-js';
import fs from 'fs';

// class内に定義
save = () => {
  const contentState = this.state.editorState.getCurrentContent();
  const content = convertToRaw(contentState);
  const filePath = "xxxxx";
    // ファイル保存処理 
    fs.writeFileSync(filePath, JSON.stringify(content), 'utf-8');
};

// import
import {convertFromRaw} from 'draft-js';
import fs from 'fs';

// class内に定義
read = () => {
  const filePath = "xxxx";
  // ファイル読み込み
  const content = fs.readFileSync(filePath, 'utf-8');

  const contentState = convertFromRaw(JSON.parse(content));
  const editorState = EditorState.createWithContent(contentState);
  this.setState({editorState});
};

まとめ

もうおわかりかもしれませんが、既に用意されている関数で十分ですね。ドキュメントにも書いてあります。
https://draftjs.org/docs/api-reference-data-conversion.html#content

きちんとドキュメントは読みましょう(戒め)

17
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
12