今年初めて実務案件で React を使用したのですが、その際に躓いたポイントをまとめていきます。
ちなみに、実務で使った開発環境は
言語: JavaScript(ES2015)
ビルド: Webpack, Babel(es2015, react, stage-0)
というかんじです。
全般
React Developer Tools
Facebook 公式による Chrome 拡張です。
現状の state の確認/書き換えとかが出来て捗ります。
key
箇条書きリストの生成などで、 array.map
して要素を出力したいときがあると思います。
その際に key
を設定してないと、
Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of
RadioFieldset
. See https://fb.me/react-warning-keys for more information.
のような警告が出ます。
key
に unique な値を設定することで、描画時の差分計算に無駄がなくなります。
例えばリストに要素を追加するときなど、他の要素は変わらないときに全体を再描画するのではなく、追加される要素部分のみを描画してくれるようになる、といったところです。
unique な値というのは、要素ごとに不変・固定であるべきもの、例えば学籍番号と名前を表示する学生リストを作るとしたら、学籍番号が適しているでしょう。
export class StudentsList extends React.Component {
render(){
const students = [
{id: 'a001', name: 'foo'},
{id: 'b002', name: 'bar'},
{id: 'c003', name: 'biz'}
];
return (
<ul>
{
students.map((student, idx)=>{
<li key={student.id}>学籍番号: {student.id} {student.name}さん</li>
})
}
</ul>
);
}
}
children
JSX による React Component の表し方は、基本的に <Class />
と、単独タグのように書くことが多いですが、 <Class></Class>
のような書き方もできます。
このように書く場合、中身は props.children
です。
例えば、以下のような見出しの Component があるとします。
class Heading extends React.Component{
render(){
const {
value,
children,
} = this.props;
return(
<header>
<h1>{value || children}</h1>
</header>
);
}
}
このとき、
<Heading value="見出しです" />
のようにも、
<Heading>
見出しです
</Heading>
のようにも書けます。
ちなみに、 children
内には任意の子DOM要素を含めることができるため、<br />
などを入れる可能性がある要素にも使えます。
<Heading>
見出しです<br />改行です
</Heading>
propTypes
propTypes を指定すると props に渡す値の型をチェックしてくれます。
MyComponent.propTypes = {
value: React.PropTypes.string
}
簡易なバリデーションのように機能し、意図しない型が入った場合はコンソールで警告されます。
また、必須の props には isRequired
を指定することで、入ってなかった場合は警告されるようになります。
MyComponent.propTypes = {
value: React.PropTypes.string.isRequired
}
defaultProps
props にデフォルト値を与えることもできます。
MyComponent.defaultProps = {
value: 'デフォルト値です'
}
propTypes と併せてさらに便利!
class の出し分け
state や props に合わせて class 名を出し分けたり、当然ありますよね。私は最初は ES2015 のテンプレートリテラルと三項演算子を組み合わせたりしていました。
class Message extends Component{
render(){
const {
type
} = this.props;
const typeclassname = type==='error'? 'is-error' : '';
return (
<div className={`message ${typeclassname}`}>
Hello, world.
</div>
);
}
}
これでも、classnames というものを同僚に教えてもらってからは、これに落ちつきました。
また、Component のスタイルには CSS Modules を使用していたのですが、 classnames の bind を使えば同様に使うことができます。
import classNames from 'classnames/bind';
const cx = classNames.bind(styles);
class Message extends Component{
render(){
const {
type
} = this.props;
const messageclassname = cx({
base: true,
isError: type==='error'
});
return (
<div className={messageclassname}>
Hello, world.
</div>
);
}
}
地味に注意するべきなのは、 import するのは classnames
じゃなくて classnames/bind
だというところですね。
持つ state を減らすための工夫
React では、state はなるべく最小限に留めた方がよしとされています。
親から渡される要素は props にし、バリデーションなど、計算して判断できるようなものは state に持たないようにします。
逆に state で持つしかないものには、入力中の値や、アコーディオンの開閉状態などが考えられます。
React 使ってみての感想(おまけ)
良かった点
React は全く初めてという状態から始めたのですが、 state も props もいらないような小さなコンポーネントから作り始め、少しずつ拡張していく、と書きながら身に付けていけたので、学習コストは低めだと感じました。
コンポーネントの粒度は悩みどころではありますが、 atomic design などを参考にし、出来る限り小さく分解できないかということを常に念頭に置いて実装していくと、まあまあうまくいきました。
このあたりはデザイナーさんと連携を取って一緒に考えていくのがベストだと思われます。
それから、 React を経験したことによって自分の中でコンポーネントという見方が強化され、それ以降の CSS 設計などにも影響が出ている気がします。
良くなかった点
JSX を書くのが地味にだるかったです……。
普段 Pug(Jade) のようなテンプレートエンジンを使い、 HTML をベタ書きすることがほとんどないのもあり、余計に煩わしさを感じました。
React-pug というものもあるらしいですが、 commit がどうやら1年前で止まっている……今回は使いませんでした。
それと、これは私が設計などをあまり調べずに書き始めたことの弊害でもあるのですが、コンポーネント間でのイベントのやりとりがバケツリレーになってしまい、つらかったです。これは Flux ベースの設計をすれば良かったので、今後はそういった設計手法も取り入れて、よりスマートな実装に近づけたいです。
全体的な印象
シンプルな view のためのライブラリで、使い方次第だなという印象を受けました。
また何かの機会で React に触れることがあれば、前述した通りですが Flux なども取り入れていきたいですね。
あと、React 触るなら ES2015 且つ babel-preset-stage-0 を入れたほうが書きやすいと思いました。
イベントハンドリングなどで、
this.hogeFunction = this.hogeChange.bind(this);
を書かなくても、
hogeFunction = () => {
...
}
と書けば良いとか、絶対こっちのほうがいいと思いましたね……