Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
25
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

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

はじめに

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

やりたい事

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

ソースやサイトはこちらです(まだアップデートする予定)

github : https://github.com/yutasuzuki/React-redux-blog/

各ライブラリの特徴を理解する

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

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

Q. React Reduxでどこから作っていけば良いのか?

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

Q. Markdownをどう管理するか?

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

'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
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になっています。


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>
    )
  }
}

まとめ

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
25
Help us understand the problem. What are the problem?