メンチカツ

ロースカツが好きです

【メモ】webpack.optimize.UglifyJsPluginでbuildしてもコメントが残っちゃうんだよねってとき

Reactアプリでリリースってなったとき、みんなやりたいのがjsファイルのminify。

webpackのドキュメント

list of plugins

に習い、webpack.config.jsで

plugins: [
  new webpack.optimize.UglifyJsPlugin({
    compress: {
        warnings: false
    }
  })
]

を追加するも、ビルドしたソースにはコメントやスペースがもりもり残ってる。。😇

そんなときはjsのloaderにoptionを追加。

module: {
    loaders: [
        {
            test: /\.js$/,
            loader: 'babel',
            query: {
                comments: false,
                compact: true
            },
            exclude: /node_modules/,
            include: __dirname
        }
    ]
}

babel-loaderのqueryに追加できるoption

babeljs.io

無事、いい感じにminifyできました。

【メモ】React,Reduxのリファクタリングはじめの一歩

よくわからないままはじめ、まさに習うより慣れよで身につけつつある Reduxスキル。 最初のほうに作ったソースを見直すと、ある共通点に気がつきました。

無駄なstateが多い!

propsで受け取った値をわざわざコピーしてstateで保持してたりします。 変更される値はイベントハンドラの引数で受け取れるので、捕捉した値を propsのイベントで上位のコンポーネントに伝搬してしまえば、stateを 用意する必要がある箇所をぐっと減らすことができました。

//before:こういうかんじの記述が多かった
handleChange(e) {
    const textValue = e.target.value
    this.setState({
        textValue: textValue
    }, this.props.onChange(textValue))
}

//after:丸投げでスッキリ
handleChange(e) {
    this.props.onChange(e.target.value)
}

変更フォームなど、propsで変更前、stateで変更後の値を保持して 比較したり、リセットボタンを押したら変更前の値に戻すとか、そういう 時以外はstateは最小限がソースが見やすいな、と思いました。

Reactで「Uncaught TypeError: Cannot read property 'props' of null」が出る

render(){
  return <myCompornent onClick={this.handleClick}></myCompornent>
}

ってやって、myCompornent側で

onClick(){
  this.props.onClick()
}

とかやると

Uncaught TypeError: Cannot read property 'props' of null

とエラーしてしまいます。

これは、

<myCompornent onClick={this.handleClick.bind(this)}></myCompornent>

とすることで回避できます。

これはes6の仕様です。es5で書かれたReactチュートリアルを写経すると発生しがちです。

qiita.com

きっちり写経したのにエラーしてしまう。。typoしてんのかな??

とか陥りがちなポイントです(というか陥った)。

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」を選択します。