Code

2016年12月29日木曜日

Website Performance checklist

 Smashing Magazine から:
 Front-End Performance Checklist 2017

 いくつか Quick Win アイテムがリストされています。その中に website を 3 秒以内ロードするとか、会社のパフォーマンスチェックチームも実施していますが、Critical Path とかは特に考えてないようです。なぜなら Adobe の AEM を使っているので、古いサイトの新しいコンポーネントベースのページが両方存在していますため。予算がないので、この2、3年は変わらないでしょうと。
 しかし、その中に、古いサイトが残していても、実施できる項目も結構あります。例えば、画像の最適化とか、FOUT / FOIT など Font 関係の Fix とか。まぁ、HTML, CSS など古いサイトでも、新しいサイト共通の部分は結構あるので、それらを精査して、一つ一つやれば、だんだんサイトが速くなります。
 JavaScript に関しては、モジュール化が絶対必要です。Tree Shaking や Code Splitting などを使って、使わないコードを最終 JS に含まないことも可能なので、ぜひチャレンジしていきたいです。例えば、Modernizr にはいろんなテストがあって、実際はほんの1、2個の Class が使われています。その他のものが必要ないので、Front End に Ship することももったいないです。
 これからも HTTP2 を考えないといけないなと。

 それでは、Happy new year!

2016年12月10日土曜日

React.js stateful component 独自で更新可能

 最近、React.js の Component を作るとき、属性を親から、子や 孫 Component まで渡すにはちょっと面倒だなと思いました。Component Tree が大変深いからです。。。
 それで色々調べて、考えました。まず解決方法として、React.js には ChildContext という概念があります。まず親でどういうデータを Context に設定するかを指定して、孫の Component などは ContextType を定義すれば、this.context でそのインスタンスがアクセスできます。しかも shouldComponentUpdate に第三の引数が nextContext となっています。ただし、もし孫の Component と親の間に、shouldComponentUpdate が false を返す親がいると、孫が更新されません。。。これは最大の問題です。
 今アプリの作りでは、childContext はちょっと使いにくいです。。。

 次となる方法としては Redux を使って、子や孫 Component に store と直接連携するようにして、もし何か state 変更が発生すれば、store からの Event がトリガーされます。これはとっても便利ですね。具体的には store からのデータを孫 Componet の state に保存して、ajax call や、どこかの View でイベントが発生したら、Redux store が自分の state を Reducer で更新して、イベントを登録している Component には送ります。その Component のイベントハンドラーで setState() を使うと、その Component のみ更新されます。とても便利です。

 それで、もう一回 React.js Component の仕組みを考えてみると、完全に独立で自分を動けます。他の Component や、アプリ他の部分と関係ありません。別に親は普通の HTML Div でも、React Component でも、Angular Directive でも。

 これはアプリが一定程度に複雑になった話しです。通常であれば、属性で関数とかを子や孫に渡すべきです。

 それでは。

Akamai Bad Request (400) Restful API Delete method

 TL; DR: If you don't have time to find the root cause, just change Delete method to Post.

 In the past several weeks, we were experiencing an issue with Akamai: in a special sequence like Get + Delete + Get, or Post + Delete + Post, the request after Delete returned a Bad Request with reference no (xxxx.xxx.0) from Akamai edge server. But it never happened in our own environment, even the prod evn behind Akamai.

 We had some meetings with Akamai support engineers. They suspected that there may be some function keeping the HTTP connection with their edge server. At first, they thought our endless scrolling function caused the issue. But in fact we just load more data at the first time, then render only the first part of the data in the screen. When user scroll, we load other parts.

 After they checked their log, they found browser is using the same TCP connection for our Delete request. Which happens in the following case:
   Get /favourites  => setting up a connect with content-length some number
   Delete /favourites/{id} => using the same connection, with content-length xxx
   Get /favourites => bad request (400) from Akamai

In this case, Akamai edge server is sending Keep-Alive header to browser, so browser may use the same TCP connection to send the Delete request => Akamai edge server counts Delete request content-length as something not correct => edge server is waiting for more data from the next request => so next Get doesn't count as a separate request, and because it doesn't match what edge server expects, edge just returns 400 bad request to browser.
(It happens as if something like nullPost, nullGet when content-length is not correct - by support engineers).

 Their explanation sounds reasonable, but I used Fiddler and Wire Shark to check the content-length for all the requests,  couldn't find any incorrect data. All numbers seemed to be correct.

 We didn't have enough time to look into this issue further, and thinking of the request after POST never fails, I changed our Restful API Delete method to Post. This fixed everything.

 I am still not sure where the problem is, but at least changing Delete to Post makes everything good...

 Hope in the future, I can get some chance to make this clear. :)

2016年11月12日土曜日

良い HTML を書こう

 最近 AEM 開発チームと一緒に仕事をしています。Front End に関してはみんな多少知っていますが、本物の Front End Dev ではないため、まぁ、結構な数の Front End Dev も Bad HTML を書いているようです。日々勉強しないと。
 さ、良い HTML ってなんでしょう?結構大きいテーマだから、とりあえず、自分の考えをリストしよう:
 ー HTML ページ全体的な構造がわかりやすく、無駄がないこと、すべての HTML Tag が正しく使われていること。例えば、<nav> や、<aside> などのタグ、とページ全体が上から、下へ、要素がロジックにあってるとか。
 ー Content First 主義。JavaScript 使ったり、CSS アニメーションを使ったり、ページは綺麗になりますが、Content はやはり第一です。ユーザーが JS を disable にすることもあるし、イメージをダウンロードしない設定もあるので、UK では 2% のユーザーがその部類らしいだそうです。(隣の Designer さんに聞いた話しです。)だから、JS などに拘らず、ページの Content はどこでも、どんなデバイスでもわかりやすく伝えられるならいいでしょう (Responsive は実は大変重要)。
 ー Accessibility は正しいこと。ページ全体の h1 や、h2 などが正しく、HTML タグに意味が正しく、どうしても HTML だけで難しい場合、ARIA 属性が正しいこと。HTML は実はそれほど動的ではないので、tab や、アコーディオンが Tag のみで難しいです。それで aria-hidden や aria-expand に使う必要ですね。
 ー ページ全体が Browser で軽くて、速いこと、いわゆるパフォーマンスが良いこと。100 ms 遅くなると、5% のユーザーを失うという記事がどこかで見たことがあるようです。具体的な数字は覚えてないけど。
CSS を <head> に、JS を <body> にロードするとか、minify とか、とにかくページを速くしないと。
 
 まぁ、ページのデザインなども重要ですが、HTML としては上記実現すれば、良い HTML だと思います。

 それでは。また後日何か思いついたら、追加します。

Pokemon Go にはまってる。。。

 Poke Index を完成するために、770 km 走った。

2016年10月16日日曜日

element.href と element.getAttribute('href') の区別

 先週、一つのバグを発見しました。まぁ、強いといえば、Back End の問題ですが、ただ引き起こされた原因は Front End にあります。
 まず、SSO をするとき、Return Url を Back End に渡していますが、もし相対 Url の場合、正しく動きますが、フルの Url を渡したら、途中で処理を止まりました。原因は Back End の処理は絶対 Url の処理はできていません。
 Domain は同じでも、Front End からどんな ReturnUrl 文字列が渡されるかはわからないので、ちゃんと処理しないと。。。

 この件、<a href="/digital/url"> を書きましたが、実際 Return Url を取得するとき、e.target.href を使ってしまいました。この場合、Browser は相対 Url に Base Url を自動的に追加します。そうすると、本来なら、相対パスであるところは絶対パスになってしまいます。。。
 解決方法は Back End 修正すべきですが、一応、 Front End も正しい動きにしたほうがいいと。e.target.getAttribute("href") にすれば、ちゃんと href 中の相対パスが取得できます。これは属性を直接使う場合、と getAttribute() 関数の違いです。
 ちなみに、jQuery はいつも getAttribute を使っているそうです。
 
 こちらは HTML Specification によると、.href を使う時は、DOM Property と呼んで、.getAttribute の場合は attribute となります。DOM Property は計算後の値になります。例えば、上記の .href。また .checked の場合、DOM Property なら true, false になりますた。.getAttribute を使うと、"" 空の文字列になる。今後ご注意を。

 それでは。

2016年10月3日月曜日

iOS での position: fixed をスムーズにする

 先日リリースした Web App の Header を position: fixed にしました。PC では問題ないですが、iOS や Android など Tablet Webkit 系では、ちょっと変な動きをしました。実際指でスクロールすると、Header が一瞬消えて、そのあと画面がほぼ静止したとき、 fixed になります。これは多分 Tablet 自身のパフォーマンス問題で、解決方法を調べてました。
 ネットではいろいろ書き込みがあります。基本的に
     transform: translate3D(0, 0, 0) を使ったり、transform: translateZ(0) を親要素に追加して、強制的に Layer を作って、ハードウェアの加速を使います。
 追加してみたら、ほぼ解決するようになりました。ただ、Header に要素が多い場合、まだまだ不自然です。デザイナーを相談して、できるだけ Header にある要素を Tablet の場合、減らしました。。。

 さらに調べてみると、transform: translate3D(0, 0, 0) か translateZ(0) を使うと、Browser はその要素を一つの Layer として、イメージを作って、Video Card のメモリにアップロードします。そのあと、何かアニメーションが起きたら、CPU の時間ではなくて、Video カードを使って、画面を更新しています。これは速いはずです。
 注意点としては、むやみにいろんな Layer を作ると、逆にパフォーマンスに悪影響が発生します。本当に使ったほうがいい時、使うよという書き込みもいっぱいあります。

 もう一つの注意点としては、新しい Layer が作られたため、z-index と translateZ(0) が衝突する可能性があります。例えば、親の間に z-index を使って、画面上の上下位置を調整していますが、親レベルですので、translateZ(0) を使うと、その z-index が効かなくなる可能性があります。よくテストしましょう。
 もう一つ、これは Tablet など画面の大きいデバイスでは、画面の小さい mobile phone では、position fixed を使わない方がいいです。media query を使って、header を元の位置に戻しましょう。
 それでは。

2016年9月18日日曜日

最新 React.js にアップデート

 先週、つい React.js のバージョンを 0.12 から 15.3 にアップグレードしました。Component 自身の修正はそんなに多くないですが、jest でのテストはかなり変わりましたので、少し時間がかかりました。
 まず、全ての node モジュールを最新バージョンにして、npm dedupe コマンドを実行して、node_modules のフォルダ構造をできるだけフラットにしました。これで、Windows でのファイル名が長すぎという git clone 時のエラーが少なくなるはずです。
 そのあと、Webpack の Config を修正して、transpile できるようにします。こちらは主に、loader の変更です。新しい Babel では、stage や、destructuring などの ES2015 フェーチャーを個々のモジュールに分けたので、preset に ES2015とReactを設定しなければなりません。こちらは .babelrc に追加します。jest も Babel loader を使うので、rc ファイルに設定したほうがいいです。そのあと、使っている ES2015 のフェーチャーを plugin に追加します。主に、destructuring になります。
 これで、transpile は通るようになります。ブラウザーで Web App をロードすると、いろんなエラーが出てきます。
 − App を DOM に render するとき、ReactDOM.render を使います。
 − getDOMNode() が削除されたので、ReactDOM.findDOMNode() に変更する必要があります。こちらは native の DOM Node div などを ref を入れると、自動的に DOM node の reference になるので、これはかなり便利になります。
 − props は完全に readonly になるので、過去の悪いコードを直しないといけません。
 − DOM node にサポートしない属性もエラーになりますので、こちらを props などの object から取り出して、設定する必要があります。例えば、contentKey とか自分で過去使っていた prop などに対して、 {...props} を使うところを { contentKey, ...others } = this.props をして、{...others} のみ React Component に渡します。
 − React Component は owner が必要とかのエラーは複数の React.js バージョンが存在したからです。過去の Third Party lib 中の React.js バージョンをチェックした方がいいです。
 − PureRenderMixin や classSet などの lib は React.js から分離されたため、個別に require する必要があります。
 こちらのエラーを直すと、基本的に Web App は動きます。

 一番大変なのは jest での Unit Tests の修正です。 setProps や、getDOMNOde() などもう使えないので、一括で findDOMNode() に変更したりして、動かない場所や、エラーになるところを一つ、一つ直す必要があります。こちらはほぼ一週間かかりました。(全部 1022 個 Unit test case)。
 なお、airbnb から enzyme というライブラリーが出てきたので、こちらをこれから使う予定です。jest よりかなり使い易いです。
 まぁ、全体的に見ると、そんなに手間をかかることではないので、早めにアップデートしたほうがいいかもしれません。

 それでは。

2016年9月10日土曜日

Web, mobile App と Restful API

 最近、作ってるアプリは Restful API を採用されました。こちらは二つの Layer があります。Web Layer と App Layer。具体的に、App Layer はデータを保存したり、処理するだけです。Web Layer は実際の Web アプリやモバイルアプリにコミュニケーションします。
 この二層 Layer は一見的に必要ないと思われてるかもしれません。ただ、API を使うとき、Web アプリとモバイルアプリの間に要求が違うときがあります。この場合、Web layer でその違いをカバーできます。さらに、JSON フォーマットの Data Contract は Web Layer で固めて、App Layer  はほぼ自由に変更できるようになります。
 例えば、Web の場合、通常ログイン状態は保持できないし、セッションタイムアウトもあります。モバイルの場合、基本的にログイン状態にあります。それで、フリーに見れるコンテンツとログインで見れるコンテンツをコントロールする必要があります。ただ、一旦ログインすると、もう扱うデータが同じになります。これは Web Layer と App Layer を分ける理由の一つです。
 もう一つの理由としては、今 AWS や Azure などの Cloud プラットフォームが使い易くなります。App Layer は自分の会社に配置して、Web Layer はAWS などを使います。App Layer も他の内部のシステムにも利用できますし、データも基本的に自社にあるから、他の会社に保存して、漏れるとかの心配も少ないでしょう。
 
 Web Layer と App Layer の間も基本的に HTTP Restful API になっています。Web Layer はアプリとの JSON Data Contract を定義して、DTO などは基本的に変更しにくいです。その後ろに存在する App Layer との間がデータのやり取りですので、変更は頻繁にあるかもしれません。アプリのバージョンが複数サポート必要があるとき、さらに使い易いです。
 それでは。

2016年8月28日日曜日

CSS Animation, Focus と Accessibility

  先日、あるアコーディオン的な Form を作って、CSS で slide up / down アニメーションをつけました。実際 CSS animation を使うとき、要素の display: none から display: block に, visibility: visible から visibility: hidden を変更すると、アニメーションが実行されません。現在 CSS animation はある数字から、次の数字までしか動きません。Height の場合、0 から 200 までアニメートできますが、0 から auto まではできません。
 では、なぜ jQuery animate 関数を使わないかと、CSS の方が効率がいいし、面白いからです。Chrome の FPS ツールでみると、CSS の場合、主に 50 FPS に一定していますが、jQuery animate は、JavaScript を実行しているので、FPS 一定ではないです。(https://greensock.com/js/speed.html)
 それで、display: none -> block の代わりに、maxHeight: 0 -> 200px を css transition でアニメートするようにしました。maxHeight 0 となっても、実際その要素は DOM に存在していますので、Screen Reader は認識しています。さらに、そのエリアに Form <input /> があるため、Tab Stop も発生しています。
 Focus が見えないところに行くのは大変良くないことです。ユーザーが Tab キーをおして、しばらく Focus はどこにあるかわからなくて、結構迷うようです。
 では、css animation を使うとき、accessibility について実装方法としては幾つかコツがあります。
 まず、<input /> みたいな Form 要素に対して、tabIndex を使って、 tab order を変更します。0 から -1 にします。0 の場合は、tab order をブラウザーを任していますが、-1 の場合、JavaScript の setFocus() 関数を使う必要があります。これで、ユーザーの Tab キーはその要素をスキップするようになります。
 次、aria-hidden を使って、見えない部分を Screen Reader から隠します。aria-hidden を true にすれば、すべての Screen Reader が読まないようになります。
 具体的に:
    <form aria-hidden={isOpen ? false : true}>
        <input tabIndex={isOpen ? 0 : -1} />
    </form>
 にするだけです。

 これで、ユーザーの Tab Stop が Form Hidden の場合、そのエリアの <input /> などに行かないように、矢印キーを使っても、その部分が読まないようになります。アニメーションは maxHeight を使って、開いたり、閉じたりできます。

 Accessibility について、いいコースがあります。英語ですけど。。。
    https://www.udacity.com/course/web-accessibility--ud891

 それでは。

2016年8月6日土曜日

React.js Component Wrapper

 先週、pre-loaded データを使って、Component を render する代わりに、ajax を使って、データロードして、そのあと、 Component を render する機能が出てきました。この機能を実現するために、Wrapper Component を作ったら、簡単にできました。
 具体的には autoLoadingComponent を作って、その中に、state を持たせて、componentDidMount の中に、ajax call を呼び出して、callback には setState() を読んで、state を更新します。この state をベースに元の Component に props として渡します。
 そうすると、state が更新するたびに、元の Component が re-render されますので、auto load 機能が実現できます。簡単な例として:

 autoLoader = React.createClass({
      mixin: [pureRenderMixin],
      getInitialState: function () {
        return {
           data: null,
           loading: true
        };
      },
      componentDidMount: function () {
         // ajax call to get data
         getJson(url, this.handleResponse);
      },
      handleResponse: function (response) {
          this.setState({
            data: response,
            loading: false
          });
      },
      render: function () {
         if (this.state.loading) {
           return <loading />;
         } else {
           return <component data={this.state.data} />;
         }
      }
   });

 これで、過去の Component も再利用できますし、どんなものでも auto load 機能がつけられます。
 さらに、Redux を使ってる場合、Redux.connect() という関数があります。この関数も同じ考え方で、state を持ってる Wrapper を作って、過去の Component を自動更新できるようにします。その中も subscribe などの biolaplate コードもいっぱい入ってます。
 
 それでは。

2016年7月24日日曜日

React.js re-render で State のクリア方法

 通常 React.js を使うと、コンポーネットを作って、DOM に render したら、たまには props を渡して、元の状態でもう一度 render したい時があります。ただ、state はコンポーネントを保持しているので、props が変更するだけで、re-render をしても、state が最初に戻らないのです。なぜなら、コンポーネントの getInitialState はコンポーネント最初の一回のみ実行されて、unmount を実行して、再 render しない限り、state は前の状態に保持されます。
 内部の操作としては、props が変更したら、React.js はコンポーネントを DOM から消して、もう一度作るではなく、変更した部分だけ再度 render するだけです。同時に、ライフサイクルの関数を見てみると、 componentDidMount は一回だけ呼び出されて、そのあとは全て、componentDidUpdate が呼び出されます。
 じゃ、どうやって、props 変更する際に state もクリアしますかと。基本的に二つ方法があります。
 まずは、componentWillReceiveProps () 関数が毎回新しい props が渡されるとき呼び出されますので、その中で props に応じて、setState を呼び出して、リセットします。  それに、この関数の中で setState で state を変更しても、re-render が起こらないです。props の変更と state の変更が一回の re-render で更新されます。他のところで、 setState を呼び出すと、shouldcomponentUpdate から render、componentDidUpdate まで一通り実行されます。これは最善策です。
 具体的に、getInitialState () で prepareInitialState を使って、新しい object を返します。親が re-render して、props が渡されたら、componentWillReceiveProps () 関数の中で、条件を判断して、もし state をクリアしたい場合、setState (prepareInitialState()) を呼び出すと、state が最初の状態に戻されます、props の変更とともに。
 もう一つの方法は props と一緒に key を変更する。key をコンポーネントに設定すると、React.js の Virtual DOM 比較アウルゴリスムはコンポーネントのタイプ、key などの属性を最初に比較します。key が変更したことは、別のコンポーネントになるわけです。
 ネットでは key を new Date() を設定して、親からの re-render があれば、変更されますので、いつもコンポーネントを最初から re-render します。

 個人的には、方法1を使うべきです。React.js はすでに componentWillReceiveProps() 関数が提供されたので、それを使うべきです。方法2としては、確かに同じ目的が達成できるかもしれないが、実行されるコードが多いのです。それに、本来なら、re-render 必要ないかもしれないサイクルでも、key が変更されて、re-render になります。全体的に複雑になります。

 それでは。

2016年7月9日土曜日

iOS 9 HTML5 モーダル スクロールできない問題

TL; DR: iOS で modal を表示しても、body が相変わらずスクロールできるの修正方法:modal-open クラスに positive: relative を追加すれば、修正されます。
 Bootstrap などを使うと、簡単に Modal ウィンドウが作れるようになります。基本的に CSS もあって、関数を呼び出すだけです。そのモーダルウィンドウは一般的に画面の真ん中に、スクロールできないようになっています。これは modal-open というクラスを body tag に設定することで、body の overflow を hidden に設定するだけでできています。
 そうすると、モーダルウィンドウ自身はスクロールできるし、いつも画面の真ん中にあります。ユーザーに操作を提示しているため、最適していると思います。
 iOS 9 がリリースされて、一つの問題は発生しました。body のスクロール禁止が効かなくなりました。
 対応方法としては
    modal-open { overflow: hidden; position: relative; }
 にして、元と同じように動きます。PC ではこの問題が起きません。

 他の修正方法としては、html, body と一緒に overflow: hidden を設定します。

 それでは。

2016年6月18日土曜日

DOM は遅い?なぜ Virtual DOM を使うか

 先日 DOM は遅いですか?なぜ Virtual DOM を使うかと聞かれました。DOM は遅いというか、DOM 操作が遅いです。ブラウザーには reflow, repaint などの処理があります。最初 HTML と CSS を分析して、ノードツリーをレンダリングした後に、JavaScript でダイナミックにノードの高さなどを変更したり、さらにノードを追加したりすると、ツリー中の他のノードを影響されるし、ツリーを再構築するかもしれません。それは当然遅いです。
 実際 HTML のノードを遍歴する時や、ノードの属性を取得するときは遅いというか、むしろ速いです。これは jQuery 自分の event システムを持つ理由もなります。一つの要素をクリックすると、その event は buble して、親要素を遡って、ルートまで達して、event handler を呼び出します。もしこの中に DOM 操作がなければ、10 ms ぐらいで、できるかと思います。
 ただし、もしノードの offsetHeight などの computed style を取得して、さらにその値をベースに、ノードの style.height を変更するときに、ブラウザーは大変な仕事になります。
 通常ではブラウザーは変更をキャッシュして、ある時間、ある程度貯まったら、画面を一気に更新します。なぜなら、細かい更新をすると、main thread が止まったりするから、ユーザーには不親切です。が、offsetHeight などの属性を取得する時、ブラウザーはできるだけ正しい値を返すために、すべての更新を実行しなければなりません。次、style.height を変更すると、さらに、ツリーの中の他のノードの位置を計算します。この Read + Write が多くなると、main thread が応答しない場合もあります。
 じゃ、どのように DOM 操作を早くできるかというと、いくつかの方法があります。
 1 要素のスタイルを変更する場合は、width, height などを個別に変更するではなくて、新しい css class を作って、要素に入れると、こちらの更新が一つの reflow, repaint で済みます。
 2 また、offsetHeight などの値取得する時や、getBoundingClientRect() 関数を呼び出す時、できるだけ、Read を完了したら、Write を行います。つまり、Read と Write を分けます。
 3 DOM 操作を一つ一つするではなくて、まずキャッシュして、一気に行ったほうがいいです。例えば、documentFragment を使って、すべての要素を入れてから、その fragment を DOM に入れるとか。まず、要素の display を none にして(隠して)、その後に、height などを変更してから、display: block にして、再表示するとか。

 他には、
 4 アニメーションをするときに、opacityや、transform, scale など一つの layer になる css 属性を使いましょう。また、アニメーション対象の要素の position を absolute にするとか。

 Virtual DOM を使う理由は上記の 3 と関係しています。JavaScript でサイトを操作するとき、Virtual DOM を使うと、変更がメモリーにキャッシュされます。すべての操作が終わったら、Virtual DOM から DOM に更新しに行きます。この場合、ブラウザーはすべての変更を一つの reflow, repaint でできるため、速いです。
 今 React.js 以外、他に incremental dommithril などいろいろ JavaScript があります。まぁ、開発はコードを書くだけではなくて、テストなども考えなければなりませんので、今の時点で React.js は一番かなと思います。
 
 それでは。

2016年6月17日金曜日

2016年6月5日日曜日

Angular から React.js への移行

 昨日今やってるプロジェクトと似ている新しいウェブアップがリリースされました。AngularJS 1.0 を使っています。マネージャーたちは使ってみたら、なぜうちのプロジェクトと比べると、遅いと感じられるかと聞かれました。そもそも AngularJS 1.0 は重いからです。ぐるぐる回るロードアイコンが止まったり、なかなか応答が返ってこなかったりしたので、そう聞かれても仕方がありませんでした。
 じゃ、どうやって、その AngularJS プロジェクトを React.js に移行するかと考えました。
 まず、AngularJS 1.0 で ng-repeat を使ってるところを directive にして、React.js を使ってレンダリングしたほうがいいと思います。原因は ng-repeat は超を付くほど重いからです。key を使っても、ajax から返ってきたデータは毎回違うから、HTML の reuse がほぼ不可能です。逆に、React.js の場合、DOM ノードは Virtual DOM をベースに更新されるので、データが変わるなら、その分のみ更新されます。DOM ノードはそのままを使うケースが結構あります。
 具体的には、ng-repeat の Collection を prop として、Component に入れます。その中で、Rendering する。directive の作り方は:
.directive('react', () => {
  return {
    scope: { data: '=' },
    link: function (scope, element, attrs) {
      scope.$watch(data, onDataChange);
      function onDataChange () {
        React.render(
          React.createElement(REACT_COMPONENT, { data: data }),
          element[0]);
        };
     }
  }
});

 これで、data が変更するたびに、React.render が呼び出されます。Virtual DOM を使っていますので、複数 rendering しても、変更する部分だけ更新されます。

 次は ng-include や ng-view を使ってる部分を切り出して、React.js に個別にレンダリングします。ReactDOM.render 関数や、React.js 自身は同じページに複数の Component をレンダリング機能がサポートしています。ng-include などは独立な Component らしいので、controller の関数を React.js Component に入れて、データバインディングを完成すれば、すぐ使えます。
 基本的に、service や、factory 部分を Flux や Redux の Store に変わるので、そんなに変更はないはずです。ただ、$http みたいな機能は React.js 提供してないから、qwest など別のライブラリを使ったほうがいいでしょう。これを考えると $http の promise が resovle されたら、$rootScope.$applyAsync 関数が呼ばれますので、ページ全体の Watcher が2回呼ばれます。。。重いですね。

 最初の一歩は一番難しいですが、変更するたびに、どんどん新しい React.js Component もできるので、やりやすくなります。最近は React.js Develop tool を使って、他のサイトはどうやっているかが見れます。
  Chrome React.js Developer tool

 例えば Airbnb などは一つ一つ Component を作って、画面に入れ替わっていることが見れます。

2016年5月22日日曜日

React.js での DOM 操作

 React.js を使うと、よくある DOM node に CSS クラスだけを設定したり、その DOM node の高さを変えたいときがあります。
 DOM 操作をする場合、componentDidMount、と componentDidUpdate 二つ箇所を考えなければなりません。最初 Component が render する場合、React.js は Virtual DOM を作成して、実際の DOM に追加されたら、componentDidMount 関数が呼び出されます。その中に、findDOMNode(this) を使ったり、this.refs.REF を使って、DOM node へのアクセスは可能です。また、component に新しい props が設定されたり、setState を読んだりすると、componentDidUpdate が最後に呼び出されます。Mount される時と同じ、DOM nodeを取得して、操作できます。
 親と子の関係について、まず子の didMount と didUpdate 関数が呼び出されて、最後に親の関数が呼び出されます。

 もし親に CSS クラスを追加する場合、setState を使うと、全 App の子 Component が re-render するので、スピードだけを比較すれば、直接 DOM を操作するほうが速いかもしれません。ただ、DOM 操作を直接やると、Virtual DOM と実際の DOM が合わなくなるので、一回やると、もう関係ある DOM の更新を全て自分でしなければなりません。App 全体の構造から見ると、それは良くないです。オススメできないです。(自分の経験から見ると、逆に面倒です。)
 この場合、shouldComponentUpdate 関数を使ったほうがいいです。まず、各 Component を作るとき、どのような props または state 値変更があったら、更新すべきかを考えたほうがいいです。その値の比較を shouldComponentUpdate の中に書いて、例えば:
    return this.props.PROP !== nextProps.PROP || this.state.STATE !== nextState.STATE;

 そうすると、親が setState を自分の state を更新して、子 Component の PROP が関係ない場合、その子の shouldComponentUpdate が false を返して、Virtual DOM の比較が行われなく済みます。
 React.js はこのような DOM 操作をまとめてします。また Browser もそのような処理が入っていて、できるだけ画面更新を一回でやりたいです。個別の DOM 操作と比べると、そんなに遅くないです。
 React.js も pure render mixin が提供しています。もし自分で shouldComponentUpdate を書きたくない場合、その mixin を使えば、同じ効果が得られます。(props で関数を子 Component 渡す時、関数の Bind を使わないように。なぜなら、bind は毎回新しい関数が返されますので、reference が更新されて、pure render mixin はいつも true となります。)

 AngularJS が最初に出た時、使い方として、directive に DOM 操作すべきとか Think in AngularJS way がありました。 React.js も同じように、できるだけ、React.js にいろんな操作をやらせるべきです。
 Think in React.js way です。

 それでは。

2016年5月1日日曜日

React.js Web App アーキテクチャー

 React.js を使うと、よく変数は Component の props により親からセットするか、State に入れて、操作するかと相談されます。また、アプリ全体として、どのように作ればいいかと度々聞かれます。
 今まで作った React App を例として:
 DOM に Render するとき <ExampleApp {...props} />
    ExampleApp の中に store からデータを取得して、state として保持。
 App 中の Component はできるだけ props を使って、データまたは callback 関数をセット。
 子 Component の中に、props を使って、データを表示したり、親の callback を読んだりする。
 必要であれば、子 Component は state も保持する。

 理由としては、React.js で Component を更新する場合、props をセットしなおす、setState({newstate}) 関数読む二つ手段があります。ExampleApp に store のデータを state に保存しているので、データが変わったら、App の setState を読んで、render 関数がもう一度呼び出して、新しい props がセットされるため、すべての子 Component が Re-render して、更新します。また子 Component 自分の state を更新する場合、子 Component の render 関数だけ呼ばれますので、App 全体のリセットが行われなくて済むので、速いです。

 注意点として、まず、props が使えるなら、props を使うべきです。state の場合、re-rendering が発生する場合、保持されますので、使うときは気をつけないと。
 次、props は readonly であるべきです。props は親から渡されるので、object の 場合、reference なので、もし間違って変更したら、親持ってるデータも同時に変更されますから、次 render する場合、props が変わってないようになったら、Component が更新されない可能性が高いです。
 子 Component から、親に onClick や、他の Component を更新すべきと通知する場合は、親からの callback を呼ぶべきです。
 onClick: function (e) { /* 子 Component 自分の操作 */
                                           this.props.parentCallback(e); }

 では、何を子 Component state に保持すべきかとういうと、例として checkbox とか form control など。その state は自分だけ使う、他の Component はそれを知らなくていいものです。もし同階層の他の Component がその値に従って、変更する場合は、親に state を保持して、props として、二つ Component に渡すべきです。

 それでは。

2016年4月10日日曜日

React.js Dev version Warning の使い方

 React.js を使うと、Webpack か Browserify と一緒に使うのがオススメです。個人的には Webpack のほうがすきです。時々 Dev バージョンに Warning が表示されたりして、Production にはそういう Warning が表示されません。それは
     ("production" !== process.env.NODE_ENV) ? Warning : other-process;
に秘密を隠れています。
 Webpack を使うと、最後の package には、Node みたいに process.env というコードが追加されます。production バージョンをコンパイルする場合、
    plugins: [
          new webpack.DefinePlugin({
              'process.env': {
                    'NODE_ENV': JSON.stringify('production')
              }
        })
      ],
が使うので、NODE_ENV は "production" になります。それで、Warning とかが実行されないようになります。
 実際のコードは Uglify を通すと、false になるところが全部消されるので、production バージョンのコードには残りません。
 通常の開発では、活用できるかなと。
 それでは、また。

React.js のほうがいい、Angular 1.0 と比べたら

 つい、来週新機能のリリースが決まりました。同時に、React.js のほうが、Angular JS 1.0 より良いと思われるようになりました。
 以前、Framework として、AngularJS 1.0 のほうが上だと思っていましたが、React.js 15.0 のリリースより、DOM が綺麗になったことで、React.js のほうが Better になりました。
 まず、data-reactid という属性がなくなりました。次、React.js によりフリーテキストに追加された<span> タグもなくなりました。これは React.js 最後の二つ問題点だと思っていましたから。これで、DOM は前より軽量に、本当の DOM のままになりました。逆に、AngularJS 1.0 の場合、ng-scope など、いろんな要素が追加されて、複雑です。
 もう一つ、最大な決め手は React.js のほうが速いです。以前 AngularJS を使うとき、ぐるぐる回る gif の Spinner 止まったり、アニメーションがカクカクしたりすることが結構ありましたが、React.js の場合、一度も見たことがありません。
 今作ってるサイトは競合サイトが結構あって、そちらは大体 AngularJS を使っています。同じ Spec のコンピューターを使うと、遅いなと思われました。特に Google Maps API で Marker を地図に入れる処理は UI が止まったようです。それは良くない User Experience です。

 さらに、React Native も少し見てみたので、Cordova とか Sencha Touch とかと違って、これは本当の Native App になります。HTML5 Hybrid App 一つの問題は遅いです。React Native を使うと、同じ概念で、本当の App が作れるし、Native のアップだから、多少無駄なコードがあっても、全然問題ないはずです。
 重要なことは一つのライブラリを使って、Web、iOS、Android 全部カバーできることです。さらにサーバーサイドレンダリングもできるので、一つのエコシステムになるような気がしています。
 これから、時間をみて、今使ってる React.js のバージョンを 15.0.1にして、早くアプグレードしようと思います。
 それでは。また。

2016年3月6日日曜日

React.js Modal Component の作り方

 いろいろ忙しいです、最近は。プロジェクトのリリースは一ヶ月伸ばされました。ビジネス側はログイン機能がほしいと言ってきたので、五月のプランに入っている Authorisation / Authentication 機能を3月いっぱいで開発することになりました。そのログイン機能はモーダルをポップアップして、ページの真ん中に表示することになっています。
 ライブラリを使おうと思ってましたが、調べてみたら、React.js 版はあまり内のプロジェクトにあわないなと思いました。それで、自分で作ろうと思いました。
 まず、そのモーダルポップアップは一つになるべきです。つまり一ページの中に一個だけにしたいです。そうすると、children を変えることで、いろんなポップアップが表示できます。次、ページの真ん中に表示するにはまず div とその overlay が必要です。
    <div className={ "modal" + this.props.showModal ? " active in" : "" }>
        {this.props.children}
    </div>
    <div className="overlay"></div>
 もちろん、overlay は pseudo-element でもできます。
 簡単ですね。:)ポップアップするときに、props.showModal を使って、active in class を追加して、画面に表示します。
 そのあとは close ボタンなどを作るだけです。
 まぁ、もし children にクローズボタンとか入れる場合、React.cloneElement を使ったりして、props を追加すればいいですね。

 AngularJS と比較すると、テンプレートベースのモーダルは ng-include を使えば、同じことができます。
 ここで、React.js のいいことは、re-render は速いです。すでにレンダリングした Component をもう一度レンダリングする場合、children の type をまず React.js を比較して、もし違うタイプだったら、ツリー全体を更新しますが、もし同じ Component の場合、更新するだけです。DOM 操作は最小限に抑えています。
 逆に AngularJS の場合、ng-include はテンプレートの string をチェックしていますので、変わってない場合は Dirty Check でスキップされます。つまり、モーダルが更新されないのです。ここで、ng-include を一回クリアするか、$timeout を使って、リフレッシュしないといけません。または自分でその テンプレートの scope 引数を親から変更したりして、更新します。また Dirty Check が一つ増えます。
 React.js の場合、わかりやすいですし、AngularJS 1.0 は面倒くさいなと。AngularJS 2.0 では scope の ダイジェスト対象が設定できるようになるので、速くなると思いますが、やはり、Component という概念は上だと思います。
 来週 Polymer を見てみよう。

2016年2月21日日曜日

React.js もっと速くするコツ

TL; DR:
    React.js Component を作る際:
 1 shouldComponentUpdate 関数は必ず入れましょう。または pureRenderMixin みたいなモジュールを使いましょう。
 2 Component は state を持つであれば、最小限の Component にしましょう。そうすると、setState は最小限 render() 関数を呼び出すし、最小限の DOM 更新します。
 3 App に state を置いて、各 Component はできるだけ props を使いましょう。もしいっぱい props があったら、Babel を使って、 {...obj} みたいなシンタックスを使いましょう。

本文:
 リリース日が近づいてきました。今作ってる Single Page Web App はもう一丁大きくなって、HTML Node の数は 20k 超えました。AngularJS の場合、もうなんかしないといけないサイズになりますが、React.js はサクサク動くだけです。この辺は DOM 操作とJavaScript 処理の差が出ました。
 ただ、React.js を使うだけで、Web App が速くなることではないと思います。やはり前書いたように AngularJS みたいに作り方次第です。AngularJS と同様、React.js Web App を速くする方法は必要なときだけ、データとDOMを更新して、また更新する必要な場所だけ更新します。
 AngularJS 1.0 の Dirty Check みたいに、React.js App を更新するには setState() という関数があります。this.setState({newState: newState}) を呼ぶと、その Component の render() 関数が呼ばれて、さらに、Component Tree の比較と行われます。そうすると、React.js は Virtual DOM の変化をキャッチして、実際の DOM を更新します。ただ、Component の render() 関数を呼ぶべきかどうかは shouldComponentUpdate() という関数がコントロールしています。デフォルトでは shouldComponentUpdate() は return true; のみです。この関数は必ず自分で書くべきです。または pureRenderMixin を使って、Component が更新必要なときだけ、true を返して、そうでない場合、false を返すべきです。
 さらに、Component は state を持つべきかどうかをよく考えないといけません。一般的に、Web App 全体の App Component に state を置いて、その他の Component は props のみ使うべきです。ただし、carousel や、toggle button みたいな自分の state が必要なとき、state を使いましょう。
 例えば、App の構造は:
    <div className="app">
        <panel1 data={this.state.data1} />
        <panel2 data={this.state.data2} />
    </div>

   App の state に data1, data2 が store から取得して、もし変化がある場合、this.setState({data1: newData}) を呼び出したら、panel1 は更新すべきですが、data2 が変わってないので、 panel2 はこの更新をスキップするために、panel2 component の shouldComponentUpdate 関数は
    return this.props.data2 !== nextProps.data2;
を書くべきです。もし data2 は複雑な object や、array の場合、deep check は難しいであれば、更新もそんなに頻繁ではない場合、いつも新しい object を作ってもいいようが気がします。
 そうでないと、React.js はいくら速くても、アプリの作りによる重くなることもありうるし、AngularJS より軽いですが、AngularJS みたい遅くなるケースもあります。

2016年1月26日火曜日

React.js Vs AngularJS、どっちがいい その3 - React.js 速い!

TL; DR: Web App のスピードにこだわりがあるなら、React.js を使おう。
追伸:新しいプロジェクトが始まる場合、AngularJS 1.0 を使わないで、できれば、AngularJS 2.0 を待ったほうがいいと思います。

 その3で isomorphic (サーバー側レンダリング)を書こうと思いましたが、Reac.js のスピードに驚いたので、まず React.js について詳しくメモしておきたいです。
 今作ってる Single Page Web App のサイズがだんだん大きくなって、ライブラリを除いて、Dev バージョンはつい 15K 行を超えました。一般的に Framework を使うと、アプリのサイズは小さくなります。ちなみに、Dev バージョンの AngularJS 1.3 は約 25K 行、React.js (Flux) は 18K 行ぐらいあります。
  Web App の DOM Node は約 9500 で、メモリは 50M ぐらいを使っています。このサイズで、経験から、AngularJS はもう重くて、Dirty Check と DOM 更新は 400ms 超えることもあります。ユーザーは遅延が感じられるサイズになります。React.js の場合、サクサク動いてて、全然遅いと感じられません。
 Framework 自身のコストもありますので、AngularJS や、Backbone.js などはすぐ DOM を更新する系は重く感じます。React.js の Virtual DOM はかなり快適に動いていることがわかります。
 これは主に shouldComponentUpdate や React.addons.PureRenderMixin うまく使った結果だと思います。
 React.js の場合、Component の state や props が更新されると、render 関数がもう一度呼び出して、Virtual DOM を更新します。さらに更新された Virtual DOM と前の Virtual DOM を比べて、変更された部分だけ DOM を更新します。さっと見ると、AngularJS 1.0 の Dirty Check とあまり変わらないじゃないかと。でも、実際はかなり違います。AngularJS 1.0 は DOM 更新を随時に行います。最初も DOM をスキャンーして、Directive を処理します。メモリなどはかなりのサイズで消耗していきます。React.js の場合、Virtual DOM の比較アルゴリズムはうまく仮想を立てて、shouldComponentUpdate もうまく利用して、本来なら O(n3) ですが、O(n) で実現できるようになりました。つまり、一回の比較で、もう変更点がわかるようになります。Dirty Check は 一回の Digest で2回実行されます。世の中間違って AngularJS を使っているアプリの中に、多分無数の $timeout を使ってるなと思って、Digest はずっと動いているかもしれません。デスクトップはいいとして、モバイルの場合、電池の消耗は速いと思われています。
 
 でも Framework や Lib は使い方次第で、スピードがかなり異なりますので、今のチームでは、うまく PureRenderMixin を使って、state と props を比較して、Component の更新が必要ないなら、shouldComponentUpdate を false を返して、render 関数をスキップします。React.js の中にも false を見ると、その Tree を比較しないようになっています。下記のページもまとめています。
 react.js advanced performance

 Component には Lifecycle があります。なんでもかんでも setState() 関数を呼び出すと、react.js もさすがに重くなります。(前のチーム開発したApp はかなり重く感じられます。React.js でよかったなと思って、AngularJS の場合はもう重くて、重くて、使えないかもしれません。)
 だから、componentDidUpdate や、componentWillReceiveProps 関数の呼び出すタイミングを測って、どのように Parent Component を更新するかとか、新しい props をもらったら、どのように state を変更するかとか細かく考えないと。できるだけ Component 不要な render 関数呼び出しを減らさないと。
 それに、component は本当に state 必要かも考えましょう。必要ないなら、stateless の component を使いましょう。

 AngularJS の機能が強いから、いろんな使い方がありますので、簡単にはアプリ全体の構造が壊されます。($timeout を使って、次の Digest を呼び出して、DOM を更新するという間違った使い方。。。)
 React.js の場合、概念が簡単だし、機能はそんなに強くないから、逆にアプリ全体がきれいに見えます。

 もし、アプリのスピードに要求がある場合、React.js を使った方がいいと思われます。