[ Electron + React ] 5分で作るMarkdown Editor

# 自己紹介

じゅんじゅんというニックネームで、関西を拠点に活動しているフロントエンドエンジニアです。

HAL大阪の2回生です👍 (2016.9.9現在)

よくstart up系イベントに行くので、大阪らへんの方は会いましょう！

# 作ったもの

今回は

- ElectronとReactで作ること

しか決まってないので、リアルタイムプレビューの機能だけしかつけていません。

できたもの。

![スクリーンショット 2016-09-09 1.24.12.png](https://qiita-image-store.s3.amazonaws.com/0/90347/c26daa51-8216-75d3-b3e8-1f1986a6ccd4.png)



# 今回作った経緯

今回は、いつもREADMEとかを書くときにsublime textのOmniMarkupPreviewerを使っていたんですが、全然動かない。。

なぜか分からないので、勉強を兼ねて作ることにしました。

今回使う技術は

- Electron
- React

ぐらいです。

Editor部分は[Ace](https://ace.c9.io/#nav=about)を使いました。

Markdownのpreviewには、[marked](https://www.npmjs.com/package/marked)を使いました。

Electronに関しては、ほぼサンプルコードのままです。

# 環境

Node v5.1.1
Electron v1.3.5

# 開発

今回の構成は

```
- app.js(electron)
- index.html
- stylesheets
    - markd.css
    - style.css
- javascripts
    - app.js
    - bundle.js
    - components
        - App.jsx
        - Editor.jsx
        - Preview.jsx
```

という感じになっています。

まずは`npm init`から始めましょう。

今回使ったモジュールは

- react
- react-dom
- marked
- react-ace
- brace
- electron-packager

開発に使うのは

- watchify
- babelify
- babel-preset-react
- babel-preset-es2015

`react-ace`はreactでaceを使うためのコンポーネントです。

`watchify`は使い差分ビルドするためで、`babelify`はES6に対応したBrowserify用のパッケージです。
`babel-preset-react`は、babelのreactのトランスパイルに使うものです。
`babel-preset-es2015`というのがありますが、ES6用のものです。ES6で書かない場合は、省いて大丈夫です！

package.jsonにこれを追記してください。

```json
  "main": "app.js",
  "scripts": {
    "start": "watchify -v -t babelify javascripts/app.js -o javascripts/bundle.js"
  },
```

では、まず`.babelrc`を書きましょう。

```
{
  "presets": ["react", "es2015"]
}
```

次に、htmlを編集します。

```html:index.html
<body>
  <div id="react"></div>
  <script src="javascripts/bundle.js></script>
</body>
```

Reactのレンダリングするための`javascripts/app.js`を編集しましょう。

```js:App.js
import React from "react";
import { render } from "react-dom";

// componentのApp.jsxをインポート
import App from "./components/App.jsx";

render(
  <App/>,
  document.getElementById("react")
)
```

では、このインポートされたApp.jsxを書いていきます。

```js:App.jsx
import React from "react";

// 後で作ります。
import Editor from "./Editor.jsx"
import Preview from "./Preview.jsx"

export default class App extends React.Component{

 constructor(){
   super();
   this._edit = this._edit.bind(this); // ES6のthisバインドされない問題があるので.bind(this)
   this.state = {
    value: ""
   }
 }

 render(){
		
  return(
   <div className="clearfix" id="app">
     <Editor
      edit={this._edit} // editorコンポーネントにeditしている間に呼ぶメソッドをpropsでわたします。
      value={this.state.value}
     />
    <Preview
      data={this.state.value} // markedでhtmlにパースするときのデータ
    />
   </div>
  );
 }

 _edit(text){
  this.setState({ value: text })
 }

}
```

特に困ることもないと思います。

```js:Editor.jsx
import React from "react";
import brace from 'brace';
import AceEditor from 'react-ace'; // aceのreact　componentを使います。

import 'brace/mode/markdown'; // modeを選ぶ
import 'brace/theme/textmate'; // カラーテーマを選ぶ

export default class Editor extends React.Component{
	
  constructor(props){
    super(props)
    this._onChange = this._onChange.bind(this);
  }

  render(){
    return(
      <AceEditor
        mode="markdown"  // mode
        theme="textmate" // theme
        width="45%"
        height="100%"
        name="editor" // id
        tabSize={2}
        showPrintMargin={false} // 真ん中らへんの線を消す
        highlightActiveLine={false} // lineのハイライトを消す
        editorProps={{$blockScrolling: true}}
        onChange={this._onChange}
        value={this.props.value}
      />
    )
  }

  _onChange(text){
    this.props.edit(text); // propsでわたってきたものを実行
  }

}
```

上二つにでてくる`this._onChange = this._onChange.bind(this)`などのものですが、これはES6で書いたときに、自動でthisをバインドしてくれないので自分で書くしかない場合の書き方です。
stage-0を使ってより簡単に記述することができます。

[ReactをES6で開発時のbindの問題](http://qiita.com/konojunya/items/fc0cfa6a56821e709065)

```js
//_onChange(){}
_onChange = () => {}
```

自作のメソッドをアロー関数をつかってかけばthisを追えるようになります。

`react-ace`のオプションなどは[react-ace](https://github.com/securingsincity/react-ace)を参照ください。

```js:Preview.jsx
import React from "react";
import marked from "marked";


export default class Preview extends React.Component{

  constructor(props){
    super(props);
  }

  render(){
    return(
      <div id="preview"
        dangerouslySetInnerHTML={{__html: marked(this.props.data)}} // reactは標準では、HTMLがエスケープされてしまうので、エスケープされないようにしないといけない。
      ></div>
    )
  }

}
```

これで全てコンポーネントを書き終えました。

`$ npm start`を実行してください。bundle.jsが出力されます。

そしたら

`$ electron app.js`

とすれば、アプリとしてこのエディタが立ちあがると思います。

おソースは全て[github](http://github.com/konojunya)にあるので、興味あるひとはぜひみてください！

[konojunya/md-preview-electron](https://github.com/konojunya/md-preview-electron)

# 最後に

React自体もそんなに難しくなく、markedもaceも余裕でしたね。

今後はexport機能とかをつけようと思います。

9/15 グランフロントでReactハンズオンします！大阪の人ぜひ！

[2時間で学ぶReactハンズオン](http://sha.connpass.com/event/39791/)

Twitter => [@konojuya](http://twitter.com/konojunya)
HP => [Hello, My World](http://konojunya.com)