React + React Bootstrap で、htmlでお知らせが書けるツールチップを使いたい
こういうやつが欲しい。
そこで
<Info message={message} />
こういうコンポーネントを作成したところ、messageに与えた文字列のhtmlタグがエスケープされて、そのまま出力されてしまう。
<Info message="Hello,<br/><br/><strong>world!!!!!!</strong>" /> // => Tooltipに「Hello,<br/><br/><strong>world!!!!!!</strong>」
それで、同じ壁にぶち当たってる人を探したら、いた。
なるほど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の呼び出しも捕捉する
はまったのでメモ
以下のようなprops
とstate
を持つコンポーネント
static propTypes = { onChange: PropTypes.func.isRequired, // this.state.selectedItemListが変更されたときに発火 itemList: PropTypes.array.isRequired, // DBからとってきたマスター的なデータ }; constructor(props) { super(props); this.state = { selectedItemList: [] //選択状態を管理する }; }
this.props.itemList
がid
とname
で構成されたデータで、
そのデータに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」をダウンロードしました。
Preferences -> Plugins -> Install plugin from disk...
でダウンロードした「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とかで 挟めないのかな、と思ったらありました。
コマンド書いたらいいんですね。
\! 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)で書けばよいそうです。
~ ─> ><}}*> 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
通った!