さわってみようreact.js、angularjs(1系、2系)
TRANSCRIPT
吉本和弘
さわってみようReact.js ・ AngularJS(1系、 2系 )
自己紹介・吉本和弘・株式会社ビズリーチ所属・サーバーサイドエンジニア
・仕事で使っている技術 Java 、 JavaScript(jQuery) 、 HTML 、 CSS MySQL 、 AWS 、 Linux 、 Android 、 iOS(Swift)
zuknow – 友達とクイズで競える学習アプリ https://www.zuknow.net/
キャリアトレック–レコメンド型転職サイト https://www.careertrek.com/
React.js・ Facebookが作った Viewのライブラリ・フレームワークでなく、UIライブラリ・ Virtual DOM DOMの状態をデータとして持ち、 状態が変化したらDOMを再生成する(差分を作成)
・コンポーネントベース・データバイディング( props )・状態管理 (state)
React.js で Virtual DOM を定義する
コンポーネントベース
- CommentBox - Comment
var Comment = React.createClass({ <div>comment</div>});var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <Comment /> </div> ); }});ReactDOM.render( React.createElement(CommentBox, null), document.getElementById('content'));
コンポーネントに DOMを定義し、コンポーネントを組み合わせる。コンポーネントの定義に従い、 DOM が生成される。
props
var CommentBox = React.createClass({ render: function() { return ( <div className=”CommentBox"> <h1>Comments</h1> <Comment data={this.data} /> </div> ); }});
var Comment = React.createClass({ render: function() { return ( <div className=“Comment"> {this.props.data} </div> ); }});
CommentBox Comment
・ data の値を受け渡す・ CommentBox で data を更新したら、 自動的に data の値を受け渡す
state
var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); }});
・コンポーネントの状態をもつ、ミュータブル(不変)な値・コンポーネント自身の状態をもつstate に対して、・ props はイミュータブル(可変)な値・ props は親の状態をもつ
{ data=[ “ コメント1” , “ コメント2”]}
props と state
var CommentBox = React.createClass({render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <Comment data={this.state.data} /> <CommentForm /> </div> ); }});
{data: “ コメント1” }
this.setState({data: “ コメント2”});
var Comment = React.createClass({render: function() { return ( <div className="comment"> {this.props.data} </div> ); }});
{data: “ コメント2”}
<div> コメント 1</div>
<div> コメント 2</div>
state
DOM
イベントハンドルvar CommentBox= React.createClass({ onClick(e) { this.setState( ・・・ ); }, render() { return ( <div> <span>click count is {this.state.count}</span> <button onClick={this.onClick}>click!</button> </div> ); }});
基本的なイベントはサポートされていて、例えば Click イベントを処理したい場合
イベントハンドル(子のイベント)
var CommentBox= React.createClass({ comment() { this.setState( ・・・ ); }, render() { return ( <div> <Comment comment={this.comment} data={this.state.data}/> </div> ); }});
子のイベントを親でハンドリングする →子のイベントを親に受け渡すイベントをハンドリングし、 state を更新する →子コンポーネントの DOM が更新される
var Comment= React.createClass({ render() { return ( <div> <button onClick= {this.props.comment}/> <p>{this.props.data}</p> </div> ); }});
サンプルプログラムの仕様・現在地周辺の飲食店の一覧を表示・一覧に表示された飲食店を お気に入りに追加できる・お気に入りをクリアできる
構築手順(1) node.js をインストール( brew install node )(2) git clone https://github.com/KazuhiroYoshimoto/sample_react_angular.git
(3) npm install package.json の内容に従って、 package がインストールされる(4) http-server
(5)「 /public/common/common.js 」の 「 COMMON.config.keyid 」にぐるなび API の KeyIdを設定
アクセス URL
1.React http://localhost:8080/react/
2.Angular1 http://localhost:8080/angular1/
3.Angular2 http://localhost:8080/angular2/
コンポーネント構成-Index -SearchResultList -SearchResult -LikeButton
Index コンポーネントで、状態管理を行う ・「検索する」ボタンのクリックイベントをハンドル → API 連携→ state 更新→ DOM が更新される ・「お気に入りに追加」ボタンのクリックイベント をハンドル→ state 更新→ DOM が更新される
Index コンポーネント・ state
・イベントハンドラ
・レンダリング
onLike: function() ・・ this.setState({shops: shops});
<div className="index"> <p> <a href="javascript:void(0);" onClick={this.onSearch}> 検索する </a> </p> <SearchResultList data={this.state.shops} onLike={this.onLike} /> </div>
onSearch: function() ・・ this.setState({shops: shops});
shops: [];
SearchResultList コンポーネント・イベントハンドラ( onLike ) 親から子に受け渡す ・レンダリング 親( Index コンポーネント)の data を取得し、 リストを JS の map 関数で出力 リストを出力するときは、 key 属性が必要
var data = this.props.data;var result = function(row,i){
return ( <SearchResult key={i} data={row} onLike={this.props.onLike}/>
);};return (
<ul>{this.props.data.map(result,this)}</ul>);
SearchResult コンポーネント・イベントハンドラ( onLike ) props で渡された id を取得 親( SearchResultList コンポーネント)の onLike 関数を呼び出す
・レンダリング
var id = this.props.data.id;this.props.onLike(id);
var shop = this.props.data;<li className="search-result"> <div>
<p> {shop.name}
</p> {imageArea}
<p> 住所 : {shop.address}</p> <LikeButton isLiked={shop.isLiked} id ={shop.id} onLike={this.onLike}/> </div></li>
LikeButton コンポーネント・イベントハンドラ クリックイベントで、 親( SearchResultList コンポーネント)の onLike 関数を呼び出す ・レンダリング
var isLiked = this.props.isLiked; if(isLiked){
return( <p> お気に入りに追加済み </p>
);}else{ return( <p><a href="javascript:void(0);" onClick={this.props.onLike}> お気に入りに追加する </a></p>
);}
AngularJS ( 1 系)・ Google 製の MVW ( Model - View - Whatever )フレームワーク ( MVC の派生パターン)・モデル(データ)とビュー(表示)によるデータバイディング・ディレクテイブ、サービス
module.controller('AppController', function($scope, $http) { // イベントハンドラ $scope.search = function() { ・・・$scope. searchShops=[ ・・・ ] };
// モデル $scope. searchShops = [{name:” お店 1”,address:” 住所 1”},{name:” お店 2”,address:” 住所 2”}
]};
AngularJS ( 1 系)データ (app.js) 画面 (index.html)
<ul> <li ng-repeat="shop in searchShops”> {{ shop.name }} {{ shop.address }} </li></ul>
$scope. searchShops
AngularJS ( 1 系)のメリット・デメリット
・大規模、複雑になったときに状態を管理するのが難しい・ルールからはずれたことをする場合に、 柔軟に対応するのが大変
メリット設計や実装のルールがある程度強制され、それに従うことで、コード量や品質の差を少なくし、生産性向上が期待できる(管理画面などの CRUD 系に有効)
デメリット
AngularJS ( 2 系)・ 1 系とは別物・コンポーネント指向、 Virtual DOM・パフォーマンス向上・ Controller や Scope は廃止・ディレクテイブ(1 系 ) <p ng-if=“??”> ・・・ </p>
(2 系 ) <p *ngIf=“??”> ・・・ </p>
AngularJS ( 2 系)var Index = ng.Component({ selector: ‘index’, // 紐づけるセレクタを指定 directives: [ng.CORE_DIRECTIVES], // 利用するディレクテイブを指定 //html を記述 template: [ ・・・ ].join('')}).Class({ onClick: function(id){ ・・・ }});document.addEventListener('DOMContentLoaded', function () {
ng.bootstrap(Index);});
app.js
index.html <index></index>