Reactでグラフ作るの巻

rechartsってやつを使ってとりあえず棒グラフを作っています。

github.com

X軸を表現するコンポーネント<XAxis>ってやつなんですが、
歯抜けなデータだと全てのlabel(tick?)が表示されないことがあるっぽいです。

その時はとりあえず以下のようinterval={0}にしておくとよいです。

<XAxis dataKey="name" interval={0} />

表データからツリー構造への変換(深さ優先探索)

できた。

深さ優先探索を使っています。
まずルートとなる要素を確定し、その要素に子要素を追加し、その子要素の子要素を…を繰り返しています。

昨日やってたのは、終端要素から親となる要素を追加していくという方法でしたが、 うまいこといかんかったので、今日は逆に子要素を追加していく方法でトライしました。
1時間もかからなかったかな。

class Converter {
  convertToTree(nodes) {
    const rootNodes = nodes.filter(node => !node.parentID)
    const rootNode = rootNodes[0]
    rootNode.children = this.buildChildNode(rootNode, nodes)
    console.log('result', rootNode)
  }

  /**
   * Depth first search
   * @param {*} parentNode
   * @param {*} nodes
   */
  buildChildNode(parentNode, nodes) {
    const parentNodeID = parentNode.id
    const childNodes = []
    nodes.forEach(node => {
      if (node.parentID === parentNodeID) {
        childNodes.push(node)
        if (node.hasChild) {
          node.children = this.buildChildNode(node, nodes)
        }
      }
    })
    return childNodes
  }
}

表データからツリー構造への変換

末尾の表データをツリー構造に変換したく色々トライしていますがうまくいかぬorz
枝の深さの数がそれぞれ違うので途中でおかしくなって破綻するパターン。

週末は普通に休みだし、いい頭の体操になるかなー。

Id parentID
1
2 1
3 1
4 1
5 1
6 2
7 6
8 6
9 6
10 3
11 3
12 3
13 3
14 4
15 14
16 15
17 4
18 5
19 15
20 19
21 19
22 19
23 19

Reactでwhy-did-you-update

お前は何故更新されたんだ?

why-did-you-updateというReactのレンダリング状況をログ出力してくれるライブラリがあります。

github.com

使い方

アプリのソースコードに以下コードを書きます。どこでもいいです。
さしあたってはエントリーポイントとなるindex.jsか、ReactDOM.renderを最初に定義しているところに書けばいいのではと思います。

import React from 'react';

if (process.env.NODE_ENV !== 'production') {
  const {whyDidYouUpdate} = require('why-did-you-update');
  whyDidYouUpdate(React);
}

使ってみた

このようなログが出ます。Google Chrome Developer Toolなどから容易に確認出来ます。

https://camo.githubusercontent.com/7e36c77c0189e3de74c986611d51111c6d96585d/68747470733a2f2f692e696d6775722e636f6d2f4e6a49345059742e706e67

例をパクらさせて頂きましたが、実際に開発しているアプリケーションに適用するとかなりログが出ること出ること請け合いです。
レンダリング前後のprops, stateの値が確認しやすくなっています。

こいつらの値をshouldComponentUpdateの中で比較してレンダリングする/しないの判断をすることになるかと。
ただ、気をつけて欲しいのが、shouldComponentUpdateを既にコンポーネントに組みこんでいる場合、why-did-you-updateさんが空気を読んでくれます。
次からそのコンポーネントのログが出なくなっちゃいます。
仕組みとしてはAOPっぽい感じがしました。

まとめ

Reactで高パフォーマンス、快適なUXを出すにはいかにコンポーネントレンダリングを減らすかにもかかっていると思うので、
why-did-you-updateは役立ちます。

ES2015でPrototype

色々残念だ。心より恥じるしかない。

class Product {
  use(str) {}
  createClone() {}
}

class Manager {
  constructor() {
    this.showcase = new Map()
  }
  register(name, product) {
    this.showcase.set(name, product)
  }
  create(name) {
    const product = this.showcase.get(name)
    return product.createClone()
  }
}

class MessageBox extends Product {
  constructor(decoChar) {
    super()
    this.decoChar = decoChar
  }

  use(str) {
    const length = str.length
    let char = ''
    for (let i = 0; i < length + 4; i++) {
      char += this.decoChar
    }
    console.log(char)
    console.log(`${this.decoChar} ${str} ${this.decoChar}`)
    char = ''
    for (let i = 0; i < length + 4; i++) {
      char += this.decoChar
    }
    console.log(char)
  }

  createClone() {
    return this
  }
}

class UnderLinePen extends Product {
  constructor(ulchar) {
    super()
    this.ulchar = ulchar
  }

  use(str) {
    const length = str.length
    console.log(`\" ${str} \"`)
    let char = ''
    for (let i = 0; i < length; i++) {
      char += this.ulchar
    }
    console.log(char)
  }
  createClone() {
    return this
  }
}

const manager = new Manager()
const upen = new UnderLinePen('~')
const mbox = new MessageBox('*')
const sbox = new MessageBox('/')
manager.register('strong message', upen)
manager.register('warning box', mbox)
manager.register('slash box', sbox)

const p1 = manager.create('strong message')
p1.use('Hello, world')
const p2 = manager.create('warning box')
p2.use('Hello, world')
const p3 = manager.create('slash box')
p3.use('Hello, world')

一番の残念ポイントは、オブジェクトのコピーをしていないところ…。
当初、Object.assign(...)を使っていたのですが、フィールドしかコピーされないんですね。(俗にいうシャローコピー)
Function含めてコピーする方法として、lodashやjQuery使うってのもありましたが、 雑に対応しちゃいました。

ES2015でSingleton

イマイチ感がすごすぎる…。

class Singleton {
  constructor() {}

  echo() {
    console.log('hello')
  }

  static getInstance() {
    if (Singleton.instance === null) {
      Singleton.instance = new Singleton()
    }
    return Singleton.instance
  }
}
Singleton.instance = null

const instance1 = Singleton.getInstance()
const instance2 = Singleton.getInstance()
console.log(instance1 === instance2)
instance1.echo()

getInstance()経由で唯一のインスタンスもらえるのはまあいいのですが、
外からnew出来ちゃうのが問題ですねこれ。

どうSingletonを実現するのがスマートなんだろうか。