React + Redux + React-Routerでブログを作りました。

## はじめに
社内の勉強会用に作りました。
できるだけシンプルなのもを作りたいと思い、ブログにしてみました。

### やりたい事
- React + Redux + React-Routerで作りたい。
- ブログっぽいものを作りたい。
- Markdownで記事は書きたい。
- シンタックスハイライトしたい。
- 管理画面は作りたくない。
- 記事を読んでいる量を表示したい。（Pocketみたいなやつ）

### ソースやサイトはこちらです（まだアップデートする予定）
github : https://github.com/yutasuzuki/React-redux-blog/

## 各ライブラリの特徴を理解する
公式サイトやREADMEを軽く目を通したり、チュートリアルをやったりしています。
その上で以下のサイトや記事、書籍がとても参考になりました。

- [[React] 入門 React ―コンポーネントベースのWebフロントエンド開発](https://www.amazon.co.jp/%E5%85%A5%E9%96%80-React-%E2%80%95%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AEWeb%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89%E9%96%8B%E7%99%BA-Frankie-Bagnardi/dp/4873117194)
- [[Redux] いまから始めるWebフロントエンド開発](https://www.amazon.co.jp/%E3%81%84%E3%81%BE%E3%81%8B%E3%82%89%E5%A7%8B%E3%82%81%E3%82%8BWeb%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89%E9%96%8B%E7%99%BA-%E6%9D%BE%E7%94%B0-%E6%89%BF%E4%B8%80-ebook/dp/B01IEKIW7U/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1486730872&sr=1-1&keywords=redux)
- [[React-Redux] たぶんこれが一番分かりやすいと思います React + Redux のフロー図解](http://qiita.com/mpyw/items/a816c6380219b1d5a3bf)
- [[redux-saga] redux-sagaで非同期処理と戦う](http://qiita.com/kuy/items/716affc808ebb3e1e8ac)

## ブログを作るに当たって考えた事

### Q. React Reduxでどこから作っていけば良いのか？
A. どこからでも良いと思うんですが、自分はcomponentから作ると作りやすいと感じました。
component → container → action → reducerって感じで作っていたと思います。

### Q. Markdownをどう管理するか？
A. MarkdownのファイルをJSONにし、fetch APIで呼ぶことにしました。
一旦、次のようなコードでJSONにしています。

```js
'use strict'
const fs = require('fs')
const path = require('path')
const util = require('util')
const md_dir = path.join(__dirname, 'md')

fs.readdir(md_dir, (err, files) =>{
  let items = []
  let settings = {
    id: [],
    titles: [],
    promises: []
  }
  files.forEach((file) => {
    const fp = path.join(md_dir, file)
    const st = fs.statSync(fp)
    const id = st.birthtime.getTime()
    const title = file.replace( /.md/g , '' )
    settings.id.push(id)
    settings.titles.push(title)
    settings.promises.push(readMarkdown(fp))
  })

  Promise.all(settings.promises).then((texts) => {
    texts.forEach((text, index) => {
      items.push({
        id: settings.id[index] + index,
        title: settings.titles[index],
        text: text
      })
    })
    fs.writeFile(`${__dirname}/data.json`, JSON.stringify(items))
  })
})

const readMarkdown = (fp) => {
  return new Promise((resolve, reject) => {
    fs.readFile(fp, {
      encoding: 'utf-8'
    }, (err, text) => {
      resolve(text)
    })
  })
}
```

### Q. シンタックスハイライトをどこで付けるのか？
A. 今回あまり良い方法が思いつかなかったので、mapStateToProps内で力技で付けています。

#### 使用ライブラリ
- showdown
- highlight.js

```js
const preTags = htmlText.match(/<pre>[\s\S]*?<\/pre>/g)
preTags.forEach((preTag) => {
  const pre = preTag.match(/<pre><code[\s\S]*?\">/i)
  const code = pre.input.replace(pre[0], '').replace(/<\/code><\/pre>/, '')
  const tag = hljs.highlightAuto(sanitize.decode(code))
  htmlText = htmlText.replace(preTag, `${pre[0]}${tag.value}</code></pre>`)
});
```

他に良い方法があれば教えて頂きたいです。

### Q. 記事を読んでいる量をどう表示するか？
A. 記事を読んでいる量をページの高さから取得しています。

始めはReduxのstateで管理していました。しかし、毎スクロールにstateが更新されるのでレンダリングの負荷が高くなってしまいました。
現在は単体で動くように管理下から外しています。（特にstate管理する必要もなかったので。）

なのでreadingScrollerとして単体のcomponentになっています。

```js

import React, { Component } from 'react'

class ReadingScroller extends Component {
  constructor(props) {
    super(props)
    this.state = {
      scrollY: this.props.scrollY
    }
    this.event = {
      readingScrollHandler: () => {
        this.getRatioScroll()
      }
    }
  }

  componentDidMount() {
    window.addEventListener('scroll', this.event.readingScrollHandler)
    window.addEventListener('resize', this.event.readingScrollHandler)
    this.getRatioScroll()
  }

  componentWillUnmount () {
    window.removeEventListener('scroll', this.event.readingScrollHandler)
    window.removeEventListener('resize', this.event.readingScrollHandler)
  }

  getRatioScroll() {
    const windowHeight = window.innerHeight
    const bodyHeight = document.body.clientHeight
    const scrollY = window.scrollY / ( bodyHeight - windowHeight ) * 100
    this.setState({ scrollY: scrollY })
  }

  render(){
    const scroller = {
      position: 'fixed',
      top: 0,
      left: 0,
      right: 0,
      width: `${this.state.scrollY}%`,
      height: '2px',
      backgroundColor: '#00a0e8',
      WebkitTransition: '.1s ease',
      transition: '.1s ease',
      zIndex: 999,
      opacity: .9,
    }
    return (
      <div style={scroller}></div>
    )
  }
}

```

## まとめ
社内勉強用に作ってきたもので、本当にこんな設計でいいのかちょっと不安ですが、作っていて楽しかったです！
また理解を深める意味でも、別のものも作って見たいと思います。