メンチカツ

ロースカツが好きです

React + React Bootstrap で、htmlでお知らせが書けるツールチップを使いたい

こういうやつが欲しい。

f:id:easy-breezy:20160608154337p:plain

そこで

<Info message={message} />

こういうコンポーネントを作成したところ、messageに与えた文字列のhtmlタグがエスケープされて、そのまま出力されてしまう。

<Info message="Hello,<br/><br/><strong>world!!!!!!</strong>" />

// => Tooltipに「Hello,<br/><br/><strong>world!!!!!!</strong>」

それで、同じ壁にぶち当たってる人を探したら、いた。

stackoverflow.com

なるほどArrayで渡せば良いらしい。

<Info message={[
    "Hello,", <br/>, <br/>,
    <strong>world!!!!!!</strong>, <br/>
]}/>

これをInfoコンポーネントの中で this.props.message.join() すればよいのか、と思いきや、

Warning: Each child in an array or iterator should have a unique "key" prop.

キーつけなさいよ!っておこられる。上のリンク先にもそうレスがありますね。

というわけでキーをつけます。

getMessage() {
        return this.props.message.map(function (m, index) {
            return <span key={index}>{m}</span>
        })
}

できあがったものはこちら。

import React, { PropTypes, Component } from 'react'
import { Tooltip, OverlayTrigger } from 'react-bootstrap'
import SHA256 from 'crypto-js/sha256'

class Info extends Component {

    static propTypes = {
        message: PropTypes.array.isRequired,
        placement: PropTypes.string
    }

    getMessage() {
        return this.props.message.map(function (row, index) {
            return <span key={index}>{row}</span>
        })
    }

    render() {
        const message = this.getMessage()
        const tooltip = <Tooltip id={SHA256(new Date()).toString()}>{message}</Tooltip>
        return (
            <span className="info">
                <OverlayTrigger placement={this.props.placement} overlay={tooltip}>
                    <i className="fa fa-info-circle"></i>
                </OverlayTrigger>
            </span>
        )
    }
}

export default Info

2016/08/10追記

パラメータのところ

<Info message={[
    "Hello,", <br/>, <br/>,
    <strong>world!!!!!!</strong>, <br/>
]}/>

は、要はjsxの書式ならOKなので、

<Info message={[<span>Hello,<br/><br/><strong>world!!!!!!</strong><br/></span>]}/>

こっちのほうがスッキリしますね。

ESLintに「"$" is not defined no-undef」と怒られた

componentDidMount() {
    $.get('/data/hoge.json', function (result) {
        this.setState({
            hogeList: result
        });
    }.bind(this));
}

上記を定義したReactコンポーネントをESLintでテストすると怒られた。

error  "$" is not defined           no-undef

これは .eslintrcのenvにjqueryを追加することで解消する。

{
  "env": {
    "jquery": true
  }
}

参考にしたページ github.com

ReactのcomponentWillReceivePropsはPropTypes.funcの呼び出しも捕捉する

はまったのでメモ

以下のようなpropsstateを持つコンポーネント

static propTypes = {
    onChange: PropTypes.func.isRequired,  // this.state.selectedItemListが変更されたときに発火
    itemList: PropTypes.array.isRequired, // DBからとってきたマスター的なデータ
};

constructor(props) {
    super(props);
    this.state = {
        selectedItemList: [] //選択状態を管理する
    };
}

this.props.itemListidnameで構成されたデータで、 そのデータにcheckboxを付与して取捨選択をさせる、というもの。 選択状態はthis.state.selectedItemListで管理する。

ちなみに、this.props.itemListには検索結果を与えるので、 変更がかかったらthis.state.selectedItemListの選択状態は 都度初期化したい。

というわけで、初期化処理をcomponentWillReceivePropsに 書いた。

componentWillReceiveProps(nextProps) {
    // this.props.itemList から選択状態を管理するthis.state.selectedItemList を生成
    var selectedItemList = [];
    nextProps.itemList.map(function (item, index) {
        selectedItemList.splice(index, 0, {
            itemId: item.id,
            checked: false, //チェック状態
        });
    });
    this.setState({
        selectedItemList: selectedItemList
    });
}

選択状態の変更時は、this.props.onChangeに最新の 選択リストを与える。

handleChange(index, checked) {
    var selectedItemList = this.state.selectedItemList;
    selectedItemList[index].checked = checked;
    this.setState({selectedItemList: selectedItemList}, this.props.onChange(selectedItemList));
}

と、this.props.onChange(selectedItemList)を コールしたところでcomponentWillReceiveProps()が走って selectedItemListが全部初期化されちゃった!orz

ので、componentWillReceivePropsを以下に書き換えた。

componentWillReceiveProps(nextProps) {
    //this.props.itemListの変更がなければbreak
    if(this.props.itemList == nextProps.itemList){
        return false;
    }
    // this.props.itemList から選択状態を管理するthis.state.selectedItemList を生成
    var selectedItemList = [];
    nextProps.itemList.map(function (item, index) {
        selectedItemList.splice(index, 0, {
            itemId: item.id,
            checked: false, //チェック状態
        });
    });
    this.setState({
        selectedItemList: selectedItemList
    });
}

問題は解消されたけれど、なんだかな。 特定のpropsだけlistenできたらいいのにな。

IntelliJ IDEA に golang プラグインを入れる

JetBrains Plugin Repository :: Go

からzipファイルをダウンロード。
ここでは「Go-0.9.748.zip」をダウンロードしました。

f:id:easy-breezy:20160113133342p:plain

Preferences -> Plugins -> Install plugin from disk...

f:id:easy-breezy:20160113133445p:plain

でダウンロードした「Go-0.9.748.zip」を選択します。

時間がかかるsqlスクリプトの進捗を確認する

mysqlスクリプトやmysqldumpで大量データをあれこれしたいとき、 なかなか終わらないと進捗が見えなくてわなわなしますよね。

# でかいテーブルを空にする
truncate table hoge_db.dekai_table;
# すごいテーブルを空にする
truncate table hoge_db.sugoi_table;

BEGIN;

# でかいテーブルに、別DBのでかいテーブルのデータを突っ込む
insert into hoge_db.dekai_table select * from fuga_db.dekai_table;
# すごいテーブルに、別DBのすごいテーブルのデータを突っ込む
insert into hoge_db.sugoi_table select * from fuga_db.sugoi_table;

COMMIT ;

トランザクションにした日には完了するまで待ち続けるしかなくて 一層わなわなします。

プロセスリスト(show full processlist)で確認することもできますが、 もうちょっと気軽にシェルスクリプトみたいに途中経過をechoとかで 挟めないのかな、と思ったらありました。

qiita.com

コマンド書いたらいいんですね。

\! echo "でかいテーブルを空にする"
truncate table hoge_db.dekai_table;
\! echo "すごいテーブルを空にする"
truncate table hoge_db.sugoi_table;

BEGIN;

\! echo "でかいテーブルに、別DBのでかいテーブルのデータを突っ込む"
insert into hoge_db.dekai_table select * from fuga_db.dekai_table;
\! echo "すごいテーブルに、別DBのすごいテーブルのデータを突っ込む"
insert into hoge_db.sugoi_table select * from fuga_db.sugoi_table;

COMMIT ;

これをnohupで実行します。nohupすることで、サーバーからログアウトした あとでも処理を続けてくれます。

$ nohup mysql -h hoge_host -u username -ppassword hoge_db -e "source sync.sql" &
#=> nohup: ignoring input and appending output to `nohup.out'

仕込んだechoは「$HOME/nohup.out」で見ることができます。

$ tail -f ~/nohup.out
#=> でかいテーブルを空にする
#=> すごいテーブルを空にする
#=> でかいテーブルに、別DBのでかいテーブルのデータを突っ込む

fish shell で $JAVA_HOME を設定する

$JAVA_HOMEに限った話ではないのですが、bashでよくやる

export JAVA_HOME=$(/usr/libexec/java_home)

みたいな、evalして変数に受け取るやつをfishでやってみた

~ ─> ><}}*> vi .config/fish/config.fish

set -x JAVA_HOME $(/usr/libexec/java_home)

ら、怒られた。

~ ─> ><}}*> source .config/fish/config.fish

$(...) is not supported. In fish, please use '(/usr/libexec/ja…)'.
.config/fish/config.fish (line 3): set -x JAVA_HOME $(/usr/libexec/java_home)
                                                    ^
from sourcing file .config/fish/config.fish
    called on standard input

source: Error while reading file '.config/fish/config.fish'

fishでは$は変数にしか使わなくて、(command)で書けばよいそうです。

stackoverflow.com

~ ─> ><}}*> vi .config/fish/config.fish

set -x JAVA_HOME (/usr/libexec/java_home)

~ ─> ><}}*> echo $JAVA_HOME

/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home

通った!

IntelliJ IDEA 14 で入力モードが思ってたんと違う

Eclipse,NetBeansからIntelliJIDEを乗り換えたところ、
入力がなんかへん。思わぬところで選択状態になったりする。
入力カーソルがvimっぽくなる。なんなのこれは。

という人は、IdeaVimというプラグインが有効になっているので
無効にすれば解消しますよ!ではー