<!DOCTYPE html>
<html class="no-js">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">window.NREUM||(NREUM={});NREUM.info={"beacon":"bam.nr-data.net","errorBeacon":"bam.nr-data.net","licenseKey":"8d5b66bcc5","applicationID":"19028431","transactionName":"e1cLFUpbX18DFE5IWEtMFk5RWldWHg==","queueTime":0,"applicationTime":245,"agent":""}</script>
<script type="text/javascript">window.NREUM||(NREUM={}),__nr_require=function(e,t,n){function r(n){if(!t[n]){var o=t[n]={exports:{}};e[n][0].call(o.exports,function(t){var o=e[n][1][t];return r(o||t)},o,o.exports)}return t[n].exports}if("function"==typeof __nr_require)return __nr_require;for(var o=0;o<n.length;o++)r(n[o]);return r}({1:[function(e,t,n){function r(){}function o(e,t,n){return function(){return i(e,[(new Date).getTime()].concat(u(arguments)),t?null:this,n),t?void 0:this}}var i=e("handle"),a=e(2),u=e(3),c=e("ee").get("tracer"),f=NREUM;"undefined"==typeof window.newrelic&&(newrelic=f);var s=["setPageViewName","setCustomAttribute","setErrorHandler","finished","addToTrace","inlineHit"],l="api-",p=l+"ixn-";a(s,function(e,t){f[t]=o(l+t,!0,"api")}),f.addPageAction=o(l+"addPageAction",!0),f.setCurrentRouteName=o(l+"routeName",!0),t.exports=newrelic,f.interaction=function(){return(new r).get()};var d=r.prototype={createTracer:function(e,t){var n={},r=this,o="function"==typeof t;return i(p+"tracer",[Date.now(),e,n],r),function(){if(c.emit((o?"":"no-")+"fn-start",[Date.now(),r,o],n),o)try{return t.apply(this,arguments)}finally{c.emit("fn-end",[Date.now()],n)}}}};a("setName,setAttribute,save,ignore,onEnd,getContext,end,get".split(","),function(e,t){d[t]=o(p+t)}),newrelic.noticeError=function(e){"string"==typeof e&&(e=new Error(e)),i("err",[e,(new Date).getTime()])}},{}],2:[function(e,t,n){function r(e,t){var n=[],r="",i=0;for(r in e)o.call(e,r)&&(n[i]=t(r,e[r]),i+=1);return n}var o=Object.prototype.hasOwnProperty;t.exports=r},{}],3:[function(e,t,n){function r(e,t,n){t||(t=0),"undefined"==typeof n&&(n=e?e.length:0);for(var r=-1,o=n-t||0,i=Array(o<0?0:o);++r<o;)i[r]=e[t+r];return i}t.exports=r},{}],ee:[function(e,t,n){function r(){}function o(e){function t(e){return e&&e instanceof r?e:e?c(e,u,i):i()}function n(n,r,o){if(!p.aborted){e&&e(n,r,o);for(var i=t(o),a=v(n),u=a.length,c=0;c<u;c++)a[c].apply(i,r);var f=s[w[n]];return f&&f.push([y,n,r,i]),i}}function d(e,t){b[e]=v(e).concat(t)}function v(e){return b[e]||[]}function g(e){return l[e]=l[e]||o(n)}function m(e,t){f(e,function(e,n){t=t||"feature",w[n]=t,t in s||(s[t]=[])})}var b={},w={},y={on:d,emit:n,get:g,listeners:v,context:t,buffer:m,abort:a,aborted:!1};return y}function i(){return new r}function a(){(s.api||s.feature)&&(p.aborted=!0,s=p.backlog={})}var u="nr@context",c=e("gos"),f=e(2),s={},l={},p=t.exports=o();p.backlog=s},{}],gos:[function(e,t,n){function r(e,t,n){if(o.call(e,t))return e[t];var r=n();if(Object.defineProperty&&Object.keys)try{return Object.defineProperty(e,t,{value:r,writable:!0,enumerable:!1}),r}catch(i){}return e[t]=r,r}var o=Object.prototype.hasOwnProperty;t.exports=r},{}],handle:[function(e,t,n){function r(e,t,n,r){o.buffer([e],r),o.emit(e,t,n)}var o=e("ee").get("handle");t.exports=r,r.ee=o},{}],id:[function(e,t,n){function r(e){var t=typeof e;return!e||"object"!==t&&"function"!==t?-1:e===window?0:a(e,i,function(){return o++})}var o=1,i="nr@id",a=e("gos");t.exports=r},{}],loader:[function(e,t,n){function r(){if(!h++){var e=y.info=NREUM.info,t=l.getElementsByTagName("script")[0];if(setTimeout(f.abort,3e4),!(e&&e.licenseKey&&e.applicationID&&t))return f.abort();c(b,function(t,n){e[t]||(e[t]=n)}),u("mark",["onload",a()],null,"api");var n=l.createElement("script");n.src="https://"+e.agent,t.parentNode.insertBefore(n,t)}}function o(){"complete"===l.readyState&&i()}function i(){u("mark",["domContent",a()],null,"api")}function a(){return(new Date).getTime()}var u=e("handle"),c=e(2),f=e("ee"),s=window,l=s.document,p="addEventListener",d="attachEvent",v=s.XMLHttpRequest,g=v&&v.prototype;NREUM.o={ST:setTimeout,CT:clearTimeout,XHR:v,REQ:s.Request,EV:s.Event,PR:s.Promise,MO:s.MutationObserver},e(1);var m=""+location,b={beacon:"bam.nr-data.net",errorBeacon:"bam.nr-data.net",agent:"js-agent.newrelic.com/nr-998.min.js"},w=v&&g&&g[p]&&!/CriOS/.test(navigator.userAgent),y=t.exports={offset:a(),origin:m,features:{},xhrWrappable:w};l[p]?(l[p]("DOMContentLoaded",i,!1),s[p]("load",r,!1)):(l[d]("onreadystatechange",o),s[d]("onload",r)),u("mark",["firstbyte",a()],null,"api");var h=0},{}]},{},["loader"]);</script>
<title>Blackbing Playground</title>
<meta name="description" content="記錄一些生活與工作的雜事，偶爾會寫一些前端網頁開發的心得">
<meta property="og:title" content="Blackbing Playground">
<meta property="og:description" content="記錄一些生活與工作的雜事，偶爾會寫一些前端網頁開發的心得">
<meta property="og:url" content="http://blackbing.logdown.com">
<meta property="og:image" content="https://s3.amazonaws.com/logdown-production/system/blog/96/og_image/52928df435b7670f9bda96bdd684735f.png">
  <meta charset="UTF-8">
  <meta name="author" content="Bingo">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <link rel="stylesheet" href="http://cdn-theme.logdown.io/frankies/stylesheets/screen.css">

  <script src="http://cdn-theme.logdown.io/frankies/javascripts/zepto.1.0.min.js"></script>
  <script src="http://cdn-theme.logdown.io/frankies/javascripts/modernizr.custom.32405.js"></script>
  <script src="http://cdn-theme.logdown.io/frankies/javascripts/main.js"></script>
  <style>.disable-hover {  pointer-events: none;} </style>
<script>
//improve mobile scroll performance
if(/Mobi/.test(navigator.userAgent)){
  $(window).on('load', function(){
    var body = document.body,
        timer,
        ts = 300;
    window.addEventListener('scroll', function() {
      clearTimeout(timer);
      if(!body.style.pointerEvents) {
        body.style.pointerEvents = 'none';
      }
      timer = setTimeout(function(){
        body.style.pointerEvents = '';
      },ts);
    }, false);    
  }); 
}
</script>
  <!-- Fallback fonts from Google Webfonts -->
    <link href="http://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css">
      <style>
        body{font-family: 'Roboto', sans-serif;}
      </style>
<meta name="robots" content="INDEX,FOLLOW">
<link rel="image_src" href="https://s3.amazonaws.com/logdown-production/system/blog/96/og_image/52928df435b7670f9bda96bdd684735f.png">


<link rel="alternate" type="application/rss+xml" title="Blackbing Playground" href="/posts.rss">
<link rel="alternate" type="application/atom+xml" title="Blackbing Playground" href="/posts.atom">
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://feeds.feedburner.com/blackbing">

<script type="text/javascript">

  var _gaq = _gaq || [];
  var pluginUrl = '//www.google-analytics.com/plugins/ga/inpage_linkid.js';
  _gaq.push(['_require', 'inpage_linkid', pluginUrl]);
  
  _gaq.push(['_setAccount', 'UA-41764280-1']);
  _gaq.push(['_trackPageview']);
  _gaq.push(['userblog._setAccount', 'UA-42623489-1']);
  _gaq.push(['userblog._trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>
</head>
<body>
  <div class="container">

    <header>
      <div class="site-header">
        <a href="http://blackbing.logdown.com" class="header-link">
          <div class="site-cover">
            <img src="https://s3.amazonaws.com/logdown-production/system/blog/96/og_image/52928df435b7670f9bda96bdd684735f.png">
          </div>
          <h1 class="site-title">Blackbing Playground</h1>
        </a>

        <div class="site-navbar">
          <nav role="navigation">
            <h3 class="hide">Blog Navigation</h3>
            <div class="site-nav-shadow"></div>
            <ul class="inline-list site-nav-links">
              <li><a href="http://blackbing.logdown.com">Home</a></li>
              <li><a href="http://blackbing.logdown.com/archives">Archives</a></li>
              <li><a href="http://feeds.feedburner.com/blackbing" target="_blank">RSS</a></li>
              <li class="search-toggle"><a href="/posts/search">Search</a></li>

              
                
                  <li><a href="http://blackbing.logdown.com/pages/about-me">About Me</a></li>
                
              
            </ul>

            <form class="site-search" accept-charset="UTF-8" action="/posts/search" method="get" role="search">

              <button class="btn-cancel" type="button" title="Cancel Search">
                <i class="icon-remove"></i>
                <span class="hide">Cancel Search</span>
              </button>

              <input class="site-search-field" name="q" type="search" placeholder="Search blog..." x-webkit-speech>

              <button class="btn-search" type="submit" title="Search">
                <i class="icon-search"></i>
                <span class="hide">Search</span>
              </button>
            </form>
          </nav>
        </div>
      </div>
    </header>

    <div class="main-content" role="main">
      

      

      

      


      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2016/07/24/we-developed-cnyes-app-with-react-native">
                
                  我們用 react-native 開發鉅亨網 app
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <p>身為一個 frontend developer，在看到 react-native 問世之後一直對 react-native 很有興趣，最近終於有機會可以碰到了，也因此才有這篇 <del>勸世文</del> 心得，本文主要想記錄一下開發到目前為止所踩過的坑，為還在 survey 技術的團隊開路。</p>
<h2>適合用 react-native 開發嗎？</h2>
<p>在接觸 <a href="https://facebook.github.io/react-native/">react-native</a> 之前，其實我們對開發 app 是還沒有信心的，一來這東西太新，二來我們也沒有實際開發過 app 的經驗，很多 UI 效果都要 survey 才知道到底做不做的到，就算 native support 也不知道 <a href="https://facebook.github.io/react-native/">react-native</a> 有沒有 support。一直到我們真的把 app 上架之後，才覺得比較有一點信心。但在開始之前，先確認一下是否有對 <a href="https://facebook.github.io/react-native/">react-native</a> 誤解：</p>
<h4>不是 write once, run everywhere，而是 learn once, write anywhere</h4>
<p>在大多數的情況下，你可以讓 Android/IOS 共用同一份 code，但這不代表你可以爽爽的不管平台問題就可以實作出功能。兩個平台畢竟還是有一些不樣的 user experience，例如 iPhone 沒有 back button，所以你需要為了 android 多處理 back button 的 behavior (<a href="https://facebook.github.io/react-native/docs/backandroid.html">BackAndroid</a>)。也因此在程式裡頭還是免不了得判斷 <a href="https://facebook.github.io/react-native/docs/platform-specific-code.html">Platform</a>。</p>

<p>例如：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="kr">const</span> <span class="nx">styles</span> <span class="o">=</span> <span class="nx">StyleSheet</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
  <span class="na">height</span><span class="p">:</span> <span class="p">(</span><span class="nx">Platform</span><span class="p">.</span><span class="nx">OS</span> <span class="o">===</span> <span class="s1">'ios'</span><span class="p">)</span> <span class="p">?</span> <span class="mi">200</span> <span class="p">:</span> <span class="mi">100</span><span class="p">,</span>
<span class="p">});</span>
</pre></div>
</figure>

<p>不過很方便的地方在於因為 react 本身就是個 view 的 engine，因此要將 component 拆開是輕而易舉的事情，而 react-native 可以讓你很輕鬆的將程式分開。</p>

<p>例如原本我們有一隻 <code>NewsDetailPagger.js</code> 的 component，但由於在實作上 Android 和 ios 上面的行為遇到不同的問題。後來就將這個 component 拆成</p>

<ul>
<li><code>NewsDetailPagger.android.js</code></li>
<li><code>NewsDetailPagger.ios.js</code></li>
</ul>

<p>就可以讓兩種平台在 compile 時就只 build 相對應的程式，也許之後也會有</p>

<ul>
<li><code>NewsDetailPagger.ms.js</code></li>
<li><code>NewsDetailPagger.tizen.js</code></li>
</ul>

<p>註：<a href="https://techcrunch.com/2016/04/13/facebooks-react-native-open-source-project-gets-backing-from-microsoft-and-samsung/">Facebook’s React Native gets backing from Microsoft and Samsung</a></p>

<p>總之，用 <a href="https://facebook.github.io/react-native/">react-native</a> 開發也是得考慮不同 platform 的問題，雖然 <a href="https://facebook.github.io/react-native/">react-native</a> 官方已經解決大多數的繁瑣的部分，但你仍須思考不同平台是否適合同一套 UI/邏輯。</p>
<h4>
<a href="https://facebook.github.io/react-native/">react-native</a> 不是 webview</h4>
<p>不要以為你原本就用 react 開發 mobile web 之後就可以移植到 react-native，基本上可共用的部分可能只有 pure 的商業邏輯，跟 view 有關的部分都會需要重寫。</p>
<h2>
<a href="https://facebook.github.io/react-native/">react-native</a> 的優點</h2>
<p>整理一下用 <a href="https://facebook.github.io/react-native/">react-native</a> 開發的優點：</p>
<h4>debug 非常方便：</h4>
<p>基本上如果只是 view 的 update，<a href="https://facebook.github.io/react-native/">react-native</a> 都已經做好 hot reload 了，只要程式碼修改就會局部 rerender。</p>
<h4>React 大幅降低學習成本</h4>
<p>如果你原本就熟悉 react 的開發流程，從 react 跳進 react-native 很快，因為原本的經驗是可以繼續累積的，包含 react, flux, redux, 各種 react performance 調效的經驗都是有用的。</p>
<h4>感受不到跟寫 web 有太大的差別</h4>
<p>一開始最讓我驚喜的其實是用 <a href="https://facebook.github.io/react-native/">react-native</a> 開發我真的不覺得我在開發 app，反而就像是多了一種特異的 browser 而已，而且 debug 也是用熟悉的 console 在 debug。<a href="https://github.com/jhen0409/react-native-debugger">react-native-debugger</a> 也可以看到 jsx 的 tree。<br>
<figure><img src="https://cloud.githubusercontent.com/assets/3001525/15636231/9e47d322-262a-11e6-8326-9a05fc73adec.png" title=""></figure></p>
<h4>專心寫你的商業邏輯</h4>
<p>基本上 <a href="https://facebook.github.io/react-native/">react-native</a> 已經處理掉大部分的效能問題，例如 <a href="https://facebook.github.io/react-native/docs/listview.html">listView</a> 已經處理了大量列表只會顯示使用者看到的部份而已。這讓開發者可以專注於產品功能的實現，不用花費太多心力在調整 UI 上的效能。</p>
<h4>
<a href="https://facebook.github.io/react-native/">react-native</a> 的生態圈非常完整</h4>
<p><a href="https://github.com/jondot/awesome-react-native/">awesome-react-native</a> 有整理了幾乎目前有的 resource ，包含教學，components 等等，看也看不完的東西。open source 的世界就是這麼迷人，based on 全世界工程師的開發與回饋造就健壯的社群。</p>
<h4>Frontend resource</h4>
<p>藉由 <a href="https://facebook.github.io/react-native/">react-native</a>，自此 frontend Engineer 可以支援 app 的開發，開發UI 上的經驗可以共用，對於組織內人力的配置也可以更加靈活彈性。</p>
<h4>UI Explorer</h4>
<p><a href="https://github.com/facebook/react-native/tree/master/Examples/UIExplorer">UI Explorer</a> 列出了幾乎所有 <a href="https://facebook.github.io/react-native/">react-native</a> 支援的 component 與範例，看 UIExplorer 有時比文件寫得更完整。</p>
<h2>
<a href="https://facebook.github.io/react-native/">react-native</a> 的缺點</h2>
<p>雖然開發到現在覺得很滿意，不過還是得列一下缺點。</p>
<h4>掰咖的 style</h4>
<p><a href="https://facebook.github.io/react-native/">react-native</a> 用 javascript 來實現 css 的設計(<a href="https://facebook.github.io/react-native/docs/style.html">style</a>)，但並不是支援所有的屬性，例如 <code>z-index</code> (<a href="https://github.com/facebook/react-native/commit/d64368b9e239b574039f4a6508bf2aeb0806121b">0.29 之後支援 ios</a>)。</p>

<p>沒有 <code>image-background</code>，沒有 <code>background-repeat</code> 等等。不過雖然少了這些東西，大部分的需求還是可以想辦法實現的，也可以藉由 <a href="https://github.com/magicismight/react-native-svg">react-native-svg</a> 做到很多漂亮的 UI。</p>
<h4>各種踩坑</h4>
<p>一開始在用 navigator 時用了 <a href="https://facebook.github.io/react-native/releases/0.30/docs/navigation.html#navigationexperimental">NavigationExperimental</a>，但由於是 experimental，每次 <a href="https://facebook.github.io/react-native/">react-native</a> 更新都有 api change，因此每次都要隨著更新。</p>

<p>像是這個新聞內頁左右翻動的功能，看似很簡單，但因為資料是動態的，所以嘗試了好幾種 pagger 的實作，最後是用 <a href="https://github.com/race604/react-native-viewpager">react-native-viewpager</a><br>
<figure><img src="https://lh3.googleusercontent.com/nrxIQQQCuICKGRm87HQRZQCbvtiiSDm64W8FyWGRaxtqXuWQVKAoYt0YNp-6MulGF_w=h900-rw" title=""></figure></p>
<h4>升級總是很痛苦</h4>
<p><a href="https://facebook.github.io/react-native/">react-native</a> 每兩週就會 realease 一個版本，這使得我們在開發到第一次上架成功之間就升級了無數次，第一個版本是 <code>0.21</code>，到目前為止已經是 <code>0.30</code>，中間有幾次升級是非常重大的更新，很多相依的 package 也要跟著更新才能順利更新上去。</p>
<h2>小結</h2>
<p><a href="https://facebook.github.io/react-native/">react-native</a> 讓前端工程師可以站在巨人的肩膀上更快速的開發，雖然到目前為止在實作中還是有許多地雷，但相信在 open source 的基礎下會更加的健壯，若您在開發的 app 功能都沒有跳脫 <a href="https://github.com/facebook/react-native/tree/master/Examples/UIExplorer">UI Explorer</a> 的範例，相信要用 <a href="https://facebook.github.io/react-native/">react-native</a> 來開發可以相對的降低開發的時間與成本。</p>
<h2>鉅亨網 App</h2>
<ul>
<li><a href="https://play.google.com/store/apps/details?id=com.cnyes.android">Android 下載連結</a></li>
<li><a href="https://itunes.apple.com/tw/app/ju-heng-cai-jing-xin-wen/id1071014509?l=zh&amp;mt=8">IOS 下載連結</a></li>
</ul>

<p>另外 <a href="https://facebook.github.io/react-native/releases/0.28/showcase.html">react-native showcase</a> 也有我們的身影喔！(不過後來因為 showcase 的政策更新被移掉了)。</p>

<p>歡迎討論 <a href="https://facebook.github.io/react-native/">react-native</a> 開發的相關問題。</p>
<h2>工商服務時間</h2>
<p>歡迎有熱情於互聯網科技、財經資訊、金融理財的專家人才<a href="https://www.104.com.tw/jobbank/custjob/index.php?r=cust&amp;j=54524b736674475e393a426b5a5c3e21940524c2f3c7447292929292840592e2d008j52&amp;jobsource=">加入鉅亨網</a>。</p>

<ul>
<li><a href="https://goo.gl/CbOQKa">Senior backend engineer</a></li>
<li><a href="https://goo.gl/tIGWWK">Backend engineer</a></li>
<li><a href="https://www.104.com.tw/job/?jobno=4s4rq&amp;jobsource=">Frontend engineer</a></li>
</ul>


              
            

            
          </div>

          

        </article>

        

      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2015/08/19/react-react-numeral-input">
                
                  [react] react-numeral-input
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <h2>react-numeral-input</h2>
<p><figure><img src="http://i.imgur.com/7eUVb7z.gif" title=""></figure></p>

<p>之前寫了一個 <a href="http://blackbing.github.io/react-numeral-input/">react-numeral-input</a>，主要是可以所見即所得的處理數字的格式，例如 100000 直接顯示為 100,000。原本的想法是將所有的輸入都轉成數字，然後將輸入的數字加上數字的格式。</p>

<p>不過這樣的作法會造成一個問題，就是當使用者在開啟輸入法時，打的任何值都會被吃掉（看起來像是鍵盤沒用的樣子）。網路上找到的解法大部分都是去做字串取代，但這樣無法解決問題。</p>
<h2>input type="number"</h2>
<p>html 的 <code>&lt;input type="number" &gt;</code> 無法顯示非數字，因此在做這個 component 時就知道不能用這個 type 了。</p>
<h2>ime-mode: disabled</h2>
<p>於是查了一下發現看起來最簡單的方法就是 disable <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/ime-mode" title="ime-mode">ime-mode</a>，但 ime-mode 只有在 firefox 和 IE 上能動。沒辦法跨瀏覽器。</p>
<h2>keycode 229</h2>
<p>接著發現當使用者用輸入法輸入時，收到的 keyCode 都是 229，也就是說是可以檢查使用者目前是開啟輸入法的，也可以提醒使用者關閉輸入法已確保正確的輸入。但麻煩的是還要額外提醒使用者的 UI 或者 notice。<br>
<figure><img src="http://user-image.logdown.io/user/96/blog/96/post/291711/qHhGMccR52ifcFdtz8uF_React-numeral-input_by_blackbing.jpg" title=""></figure></p>
<h2>User Feedback</h2>
<p>轉個念一想，其實問題是在使用者輸入時，沒有對應的 user feedback 給他，才會造成誤解欄位無法輸入的情況，因此保留不正確的格式好像也不是一個問題？<br>
<figure><img src="http://user-image.logdown.io/user/96/blog/96/post/291711/M3qzB4vpQx6kpJdTgstI_%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7_2015-08-19_%E4%B8%8B%E5%8D%884_42_28%EF%BC%882%EF%BC%89.jpg" title=""></figure></p>

<p>這樣就不需要去考慮輸入法什麼問題，類似這種所見即所得的工具，可以改變使用者的輸入，但要避免讓使用者誤解「輸入 -&gt; 輸出沒反應。」</p>
<h2>結論</h2>
<p>如此要解決的問題就顯得容易的多，當你在輸入時開啟輸入法，還是可以輸入，但程式不會將你輸入錯的值吃掉，而是返回給試用者，至於是否要顯示 error message，則交給系統自己決定即可。看似簡單的問題，卻繞了一大圈回來才想到解法。</p>
<h2>DEMO</h2>
<p>有興趣的人可以玩玩看　<a href="http://blackbing.github.io/react-numeral-input/">react-numeral-input</a>，或是直接安裝</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre>npm install react-numeral-input --save-dev
</pre></div>
</figure>


              
            

            
          </div>

          

        </article>

        

      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2015/07/06/javascript-use-the-deferred-processing-dynamic-order-of-tasks">
                
                  [javascript] 利用 Deferred 處理動態的順序性任務
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <h2>前情提要</h2>
<p>之前寫了一篇 <a href="http://blog.blackbing.net/post/2014/05/09/javascript-deferred-ordered-task">利用 Deferred 處理順序性任務</a>，主要是利用 Deferred 來避免 callback 寫法的缺點。</p>

<p>不過在實務上，可能會遇到更複雜一點的情況，例如：</p>

<p><figure><img src="http://user-image.logdown.io/user/96/blog/96/post/283654/YRrJI9GS9SXRQayfKcSp_pipe%20array%20flow%20(2).png" title=""></figure></p>

<p>這張圖的意思是要確保任務是 A-&gt;B-&gt;C　的執行順序，而且當 A,B,C　有任一個 fail　就會停止，不會再執行下去。我們直接來看應該要怎麼處理這樣的程式。</p>
<h2>範例</h2>
<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">Deferred</span><span class="p">();</span>
<span class="kd">var</span> <span class="nx">b</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">Deferred</span><span class="p">();</span>
<span class="kd">var</span> <span class="nx">c</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">Deferred</span><span class="p">();</span>

<span class="kd">var</span> <span class="nx">checkA</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'checkA'</span><span class="p">);</span>
  <span class="k">return</span> <span class="nx">a</span><span class="p">.</span><span class="nx">reject</span><span class="p">();</span>
<span class="p">};</span>
<span class="kd">var</span> <span class="nx">checkB</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'checkB'</span><span class="p">);</span>
  <span class="k">return</span> <span class="nx">b</span><span class="p">.</span><span class="nx">resolve</span><span class="p">();</span>
<span class="p">};</span>
<span class="kd">var</span> <span class="nx">checkC</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'checkC'</span><span class="p">);</span>
  <span class="k">return</span> <span class="nx">c</span><span class="p">.</span><span class="nx">reject</span><span class="p">();</span>
<span class="p">};</span>

<span class="kd">var</span> <span class="nx">checkAll</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
  <span class="kd">var</span> <span class="nx">_dfr</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">Deferred</span><span class="p">().</span><span class="nx">resolve</span><span class="p">();</span>
  <span class="nx">_dfr</span> <span class="o">=</span> <span class="nx">_dfr</span>
    <span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">checkA</span><span class="p">)</span>
    <span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">checkB</span><span class="p">)</span>
    <span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">checkC</span><span class="p">);</span>
  <span class="k">return</span> <span class="nx">_dfr</span><span class="p">.</span><span class="nx">promise</span><span class="p">();</span>
<span class="p">};</span>

<span class="nx">checkAll</span><span class="p">().</span><span class="nx">done</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">return</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'checkAll done'</span><span class="p">);</span>
<span class="p">}).</span><span class="nx">fail</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">return</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'checkAll fail'</span><span class="p">);</span>
<span class="p">});</span>
</pre></div>
</figure>

<p>為了簡化程式，我直接在 checkA/B/C　的 function 中回傳 Deferred reject or resolve。上述的例子可以直接看<a href="http://jsbin.com/yegipo/edit?js,console">結果</a>。<br>
可以看到結果只會印出</p>

<figure class="figure-code code"><div class="highlight"><pre>"checkA"
"checkAll fail"
</pre></div>
</figure>

<p>是因為 checkA 執行時就被 reject 了，因此不會再繼續執行下去。您可以自己試試看將 reject 改成 resolve　看一下執行的結果會變成怎麼樣。</p>
<h2>Dynamic task function</h2>
<p>實務操作上 task 也許會是動態的，我們可以很簡單的將任務指派成一個 array 的形式，例如：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="kd">var</span> <span class="nx">funList</span> <span class="o">=</span> <span class="p">[</span><span class="nx">checkA</span><span class="p">,</span> <span class="nx">checkB</span><span class="p">,</span> <span class="nx">checkC</span><span class="p">];</span>
</pre></div>
</figure>

<p>然後將 checkAll 的任務串起來</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="kd">var</span> <span class="nx">checkAll</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
  <span class="kd">var</span> <span class="nx">_dfr</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">Deferred</span><span class="p">().</span><span class="nx">resolve</span><span class="p">();</span>
  <span class="kd">var</span> <span class="nx">funList</span> <span class="o">=</span> <span class="p">[</span><span class="nx">checkA</span><span class="p">,</span> <span class="nx">checkB</span><span class="p">,</span> <span class="nx">checkC</span><span class="p">];</span>
  <span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o">&lt;</span><span class="nx">funList</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
    <span class="nx">_dfr</span> <span class="o">=</span> <span class="nx">_dfr</span><span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">funList</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="nx">_dfr</span><span class="p">.</span><span class="nx">promise</span><span class="p">();</span>
<span class="p">};</span>
</pre></div>
</figure>

<p>最後的程式碼結果請<a href="http://jsbin.com/decuga/edit?js,console">猛擊這裡</a></p>
<h2>結論</h2>
<p>要注意的是不能用 <a href="https://api.jquery.com/jQuery.when/">jQuery.when</a>，when 是一次發出去執行，會等到全部做完才會回來。</p>
<h2>Reference</h2>
<ul>
<li><a href="http://stackoverflow.com/questions/11833851/jquery-deferred-with-an-array-of-functions/31241768#31241768">jQuery Deferred with an array of functions</a></li>
</ul>


              
            

            
          </div>

          

        </article>

        

      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2015/04/15/react-selection-auto-complete-component">
                
                  [react] selection auto-complete component
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <p>最近在找一個 selection 的 react component，但希望可以支援 auto-complete，找了好幾個不是整合有問題，就是彈性不夠，試了幾個都不太好整合。後來找到這個，<a href="http://jedwatson.github.io/react-select/">http://jedwatson.github.io/react-select/</a>，蠻不錯的 UI，想要的功能也都支援。特此記錄一下。</p>
<h2><a href="https://github.com/JedWatson/react-select">react-select</a></h2>
<p><a href="http://jedwatson.github.io/react-select/">demo</a></p>

<p><figure><img src="http://user-image.logdown.io/user/96/blog/96/post/260367/d5i4FaOQXSeNg4AWIvwQ_%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202015-04-15%20%E4%B8%8B%E5%8D%882.45.56.png" title=""></figure><br>
蠻喜歡這種 UI 的，兼具 input 和 select 的控制項。</p>
<h3>以下是其他類似的，但用過都還是有缺點</h3>
<ol>
<li>
<a href="https://github.com/asbjornenge/react-datalist">https://github.com/asbjornenge/react-datalist</a>
利用 <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist">html5 datalist</a>，用 react 的特性其實很好操作，缺點是 支援瀏覽器有限(<a href="http://caniuse.com/#search=datalist">http://caniuse.com/#search=datalist</a>)，polyfill 太醜然後某些 action 操作不太一樣。</li>
<li>
<a href="https://github.com/fmoo/react-typeahead">https://github.com/fmoo/react-typeahead</a> 
看到 typeahead 我以為是 twitter 的 <a href="https://twitter.github.io/typeahead.js/">typeahead</a> 的 react 版本，後來看了 sourcecode 才發現作者是重頭實做了一次 typeahead ，但是很多部分跟原本的 typeahead 不太一樣。操作起來綁手綁腳的。</li>
<li><p><a href="https://github.com/eliseumds/react-autocomplete">https://github.com/eliseumds/react-autocomplete</a><br>
這個 repository 取名取得很好不過跟 npm 的 <a href="https://www.npmjs.com/package/react-autocomplete">react-autocomplete</a> 又不一樣，然後 npm 的 react-autocomplete 的命名其實是 combobox ，而且沒在維護，連 source code 也不在 github 上了。</p></li>
<li><p><a href="https://github.com/prometheusresearch/react-selectbox">https://github.com/prometheusresearch/react-selectbox</a><br>
因為星星數不夠多，所以根本沒用過。</p></li>
</ol>

<p>以上。雖然網路資源很多，但是找起來好像在查 paper 的感覺，希望有幫助到有相關需求的人。</p>


              
            

            
          </div>

          

        </article>

        

      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2015/01/19/secrets-on-npm-packagejson">
                
                  Secrets in npm package.json
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <h3>講個秘訣</h3>
<p>在用 npm 來管理 node package 時，愚昧如我只會用 <code>npm install</code> 來 install package，在歷經一些痛苦之後決定好好來看一下 package.json 的秘密。</p>
<h2>dependencies V.S. devDependencies</h2>
<p>區分專案的開發時的模組相依性。一般來說開發時都會用 <code>npm i $PACKAGE_NAME --save-dev</code> 這樣就會設定成該模組的 devDependency。但如果參數是給 <code>--save</code> 就會是 dependency。這是用來區別 production mode 時不需要下載 devDependency 的 package。</p>

<p>需要注意的是，<code>npm install</code> 預設會載入 devDependency 的 package，若是在 production mode 時，要做<br>
 <code>npm i --production</code> 指定只載入 dependency 的 package，如此就不會多載入一些開發才需要用到的 package。</p>
<h2>npm scripts</h2>
<p>不知道有沒有人跟我一樣，看到 Caesar 大大這個討論串，<a href="https://www.facebook.com/clonncd/posts/10153426073214838?pnref=story">多想三秒，其實可以不用 grunt &amp; gulp.</a>，才發現原來 npm 可以自訂 scripts，然後傻傻的打 <code>npm watch</code>，結果不能執行，後來查了一下才知道 npm 有預設的指令，如果要執行自訂的指令要用 <code>npm run xxx</code>來執行。所以可以搭配一些 shell 指令來簡單的做你想做的事情。</p>
<h3>pre/post scripts</h3>
<p>然後在看 npm scripts 時看到一個蠻有趣的用法。</p>

<blockquote>
<p>Pre and post commands with matching names will be run for those as well (e.g. premyscript, myscript, postmyscript).</p>
</blockquote>

<p>簡單來說可以分開執行 script 的順序，在做複雜的指令還蠻好用的。 例如你可以自訂：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="p">{</span><span class="w">
  </span><span class="nt">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nt">"bingo"</span><span class="p">:</span><span class="w"> </span><span class="s2">"echo Bingo"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></div>
</figure>

<p>所以當執行 <code>npm bingo</code> 就會 echo <code>Bingo</code>，接著加上 pre/post 的話，例如：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="p">{</span><span class="w">
  </span><span class="nt">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nt">"bingo"</span><span class="p">:</span><span class="w"> </span><span class="s2">"echo Bingo"</span><span class="p">,</span><span class="w">
    </span><span class="nt">"prebingo"</span><span class="p">:</span><span class="w"> </span><span class="s2">"echo Hello"</span><span class="p">,</span><span class="w">
    </span><span class="nt">"postbingo"</span><span class="p">:</span><span class="w"> </span><span class="s2">"echo World"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></div>
</figure>

<p>這樣執行 <code>npm bingo</code> 就會 echo </p>

<figure class="figure-code code"><div class="highlight"><pre>Hello
Bingo
World
</pre></div>
</figure>

<p>舉例來說，我會搭配 bower 來管理前端需要用的 package，我就可以加上 postinstall 的指令來做 bower install。</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="p">{</span><span class="w">
  </span><span class="nt">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nt">"postinstall"</span><span class="p">:</span><span class="w"> </span><span class="s2">"bower install"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></div>
</figure>

<p>當執行 <code>npm install</code> 之後就會接著做 <code>bower install</code>。</p>

<p>所以 <strong>ReadME</strong> 就不用再寫 Step1, Step2, ...。只要 <code>npm install</code> 就可以搞定啦，而且 jenkins 的 job 設定也可以變的比較一致性了，專案自己該做的事情就寫在這些 scripts 即可。回過頭來說，<strong>「多想三秒，你真的可以不用 grunt &amp; gulp.」</strong></p>
<h2>package version control</h2>
<p>不知道有沒有人注意到，在執行 <code>npm install $PACKAGE_NAME</code> 時，他會指定成 "^1.2.3"，這是 follow <a href="https://github.com/npm/node-semver" rel="nofollow" target="_blank">https://github.com/npm/node-semver</a> 的版本號規則。</p>

<p>需要注意的是預設的 "^1.2.3"，意思是 <code>[ '&gt;=1.2.3-0', '&lt;2.0.0-0' ]</code>，所以若 package 版本有更新，會自己升上去。最近幾次有遇到 jenkins 自己莫名其妙 build fail 就是因為版本不同而造成的問題。建議可以改成 "~1.2.3" <code>[ '&gt;=1.2.3', '&lt;1.3.0' ]</code> 或是寫死版本 "=1.2.3"，再視專案而定更新就好。團隊開發時版本的控制很重要，沒有指定好大家拉不同的 code 常常會造成浪費時間的 debug。其他更詳細的用法就在參考 <a href="https://github.com/npm/node-semver" rel="nofollow" target="_blank">https://github.com/npm/node-semver</a> 囉。</p>
<h2>npm outdated</h2>
<p>有空可以執行 <code>npm outdated</code> 來檢查 package 的更新，視情況而決定是否要更新 package。建議是開 feature branch 來做 upgrade package，沒問題再 merge 回去。</p>

<p>以上，這些大概是開發常會遇到的一些心得與秘訣，如果想看更詳細的解釋就請直接看 doc 啦。</p>
<h2>References:</h2>
<ul>
<li><a href="https://docs.npmjs.com/files/package.json" rel="nofollow" target="_blank">https://docs.npmjs.com/files/package.json</a></li>
<li><a href="https://docs.npmjs.com/misc/scripts" rel="nofollow" target="_blank">https://docs.npmjs.com/misc/scripts</a></li>
<li><a href="https://github.com/npm/node-semver" rel="nofollow" target="_blank">https://github.com/npm/node-semver</a></li>
</ul>


              
            

            
          </div>

          

        </article>

        

      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2014/12/25/wedding-party-hackday">
                
                  Wedding Party Hackday
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <p><figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/mqRU7dBQLyWBDSdSzFFR_16.jpg" title=""></figure><br>
最近完成了終身大事，也終於有點時間記錄一下了，身為一個宅宅工程師，我堅持自己的婚禮也要充斥一點宅味，當然也要感謝我的老婆容忍我的任性(疑~)。</p>

<p>其實很久以前就想過婚禮時可以做哪些系統了，有鑑於大家都說到時候不會有時間做這些事情，於是我提早開始準備我要做的系統。</p>
<h2>互動式婚紗照片</h2>
<p>我一直覺得婚紗本又重又難收藏，所以我很早就想把婚紗照直接用螢幕輸出，但只做播放太無聊了，所以我想要加入一些互動的元素，很直覺就想到用「motion detect」來做翻頁。</p>
<h3>gest.js</h3>
<p><a href="https://github.com/hadimichael/gest.js">gest.js</a>這套 Library 可以用 camera 來辨識揮手的動作，辨識上下左右。試了一下辨識度還不錯。</p>
<h3>jssor slider</h3>
<p>要找適合的 slider library 反而找比較久，因為我希望可以支援上下左右的滑動效果，自動播放時也有一些客製化的特效，但大部分的 slide show 都只有左右滑動，最後找到這個客製化程度蠻高的 library <a href="http://www.jssor.com/">jssor slider</a> ，實際使用時其實他也沒辦法直接用上下滑動，所以我有修改了他的原始碼，讓他可以支援動態改變左右滑動與上下滑動。</p>

<p>最後就生出來這個版本了：<a href="http://blackbing.github.io/wedding-slides/">DEMO</a>，有興趣玩的人只要把 /image/photos/ 底下的照片換掉即可。有空我再寫 README。</p>

<p><figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/zRONPykqQDeTug9QIsQt_10850072_10152841915926539_3126894732238031620_n.jpg" title=""></figure></p>

<p>現場是用 iMac 顯示，然後在桌上弄點布置這樣，真是頗具巧思（自己說）。不過事實證明，沒有人介紹的話其實鮮少有人會發現可以用手控制，然後應該是小孩比較有興趣而已XD。</p>
<h2>婚禮留言板</h2>
<p>這個是我一直想做的東西，每次參加婚禮在開場前賓客都會不知道要幹嘛，早到的朋友會有點無聊，為了增加一點互動性，應該安排一些小活動給大家玩，類似的東西就是實體的留言箱，大家發一張小卡，然後上面些一些祝福的話，最後新人抽獎出來之類，不過因為沒有辦法看到大家的留言，少了一點即時的參與感。於是我又打算 web 化（沒辦法，我只會這個XD），讓賓客用手機留言，然後即時顯示在投影布幕上。</p>
<h3>桌卡</h3>
<p>桌卡的範本來自於 <a href="http://www.mybigday.com.tw/">mybigday</a> (個人覺得不好用)，不過我用了他的桌卡範本改成我要的格式，放了 QR code 和連結上去。<br>
<figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/Zm64DwbQxaFr82o1Hbjc_%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202014-12-25%2013.43.32.png" title=""></figure></p>
<h3>手機留言</h3>
<p><figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/4MNMeIEeQDifpk0MGRXU_c21c5f114d9bbcba443f0d334b36f5ed%20(1).jpg" title=""></figure></p>
<h3>留言板</h3>
<p><figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/4Pt7ZxlBQ0SaQtgW8vTW_%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202014-12-25%2013.20.21.png" title=""></figure></p>
<h2>抽獎活動</h2>
<p>留言當然要用點誘因來讓大家留言囉，於是我做了一個透過手機抽獎，可以讓主持人邀請重要嘉賓抽獎的部分。<br>
<figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/8QkXHljeTyeT11spIxsz_c21c5f114d9bbcba443f0d334b36f5ed.jpg" title=""></figure></p>

<p>最後的重頭戲就是抽獎了，由於前陣子很愛玩 ranger ，而且他的抽獎動畫實在是太可愛了，所以我就把裡面的動畫擷取出來做抽獎，效果不錯（自己說）。<br>
<figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/t89gl9xrScqV5HLJKCmq_%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202014-12-25%2013.19.11.png" title=""></figure></p>
<h2>小插曲</h2>
<p>千古不變的定律， live demo 一定會出狀況，當天果然也是，原因是我以為 facebookid 都會拿到一串數字，結果我自己白痴塞了一些預設的 string id 進去，本來是拿數字 id 來取 mod 所以就出狀況了。好在我有堅強的 HTC FE 團隊協助我當場的 debug（hug)。<br>
<figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/4tNDtMcgScixdATOowVQ_1619141_10201994217896298_4293646646054564328_n.jpg" title=""></figure></p>

<p><figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/ZqoeGoRlR1awX33FDB7h_10806202_10201994262017401_6262181042209528548_n.jpg" title=""></figure></p>
<h2>總結</h2>
<ol>
<li>QR code 很不普及。</li>
<li>桌卡做的太假掰，有人以為是餐廳的根本不想理。</li>
<li>非常非常需要 promote，下次有機會（疑？）應該要請工作人員一桌一桌介紹或施加壓力(?)留言，要讓大家更有參與感一點，最後的抽獎才會 high。</li>
<li>其實只是搞死自己而已，其實我程式早在兩個月前就準備好了，不過婚禮前幾個禮拜測試發現 firebase 的 auth 部分改版了，結果為了要測 auth 的部分又花了一些時間修改程式。中間一度想要放棄這個活動。下次有機會（疑？）就乖乖的走完流成就好了。</li>
<li>我老婆好票釀。</li>
<li>謝謝大家的參與，大家下次見（疑？）</li>
<li>我愛我老婆。</li>
</ol>

<p><figure><img src="http://user-image.logdown.io/user/96/blog/96/post/247477/zEd6FF0AQEaiefBCUdoP_62.jpg" title=""></figure></p>

<p>最後順便打個廣告，如果有人對這個留言系統和抽獎程式有興趣的話請來信聯絡，保證以友情價情義相挺。</p>


              
            

            
          </div>

          

        </article>

        

      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2014/08/08/reactjs-jsx-tips-with-coffeescript">
                
                  [ReactJS] tips of Writting JSX with CoffeeScript
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <p>由於一開始我沒有認真看 JSX (而且也很懶得看)就開始使用 coffeescript 來寫 React 了，所以一直沒有去搞懂 JSX 到底要怎麼寫，直到最近才開始認真使用 JSX 來開發，<a href="/post/2014/08/05/reactjs-jsx-or-coffee-style">詳看上集</a>。關於 jsx 的 tip 其實官方有介紹一些技巧與注意事項：可以參考 <a href="http://facebook.github.io/react/tips/introduction.html">React Tips Introduction</a>。</p>

<p>因為自己習慣用 coffee 的關係，所以會遇到一些小問題，這篇文章主要紀錄一下用 coffee 寫 react 需要注意的地方與心得，本篇文章的程式碼也都是 coffeescript。</p>
<h3>browserify</h3>
<p>強烈建議一定要使用 <a href="http://browserify.org/">browserify</a> ，官方寫的 <a href="https://github.com/facebook/react/tree/master/examples/todomvc-flux">todomvc-flux</a>就是用 <a href="http://browserify.org/">browserify</a> 來打包程式的，用了 <a href="http://browserify.org/">browserify</a> 之後就可以用 <a href="https://github.com/substack/coffeeify">coffeeify</a> 和 <a href="https://github.com/andreypopp/reactify">reactify</a> 來 compile 程式了。</p>

<p>關於 browserify 的設定可以參考我的專案設定 <a href="https://github.com/blackbing/htccs-webapp/blob/master/gulp/tasks/browserify.coffee" rel="nofollow" target="_blank">https://github.com/blackbing/htccs-webapp/blob/master/gulp/tasks/browserify.coffee</a></p>
<h3>jsx header</h3>
<p>若程式之中有需要做 reactify 的程式要在第一行加上這行，讓 reactify 認得要 parse jsx 語法。</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="o">`</span><span class="sr">/** @jsx React.DOM */</span><span class="o">`</span>
</pre></div>
</figure>
<h3>jsx component</h3>
<p>jsx 特有的語法就是用 element tag name 來當語法，例如：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="kd">var</span> <span class="nx">HelloMessage</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createClass</span><span class="p">({</span>
  <span class="na">render</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/div&gt;;</span><span class="err">
</span>  <span class="p">}</span>
<span class="p">});</span>
</pre></div>
</figure>

<p>用 coffee 來撰寫時就會用到<code>``</code>來轉成 javascript 再交給 reactify 來處理。</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">HelloMessage</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="na">createClass</span><span class="p">(</span>
  <span class="na">render</span><span class="o">:</span> <span class="p">()</span><span class="o">-&gt;</span>
    <span class="k">return</span> <span class="o">`&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="na">props</span><span class="p">.</span><span class="na">name</span><span class="p">}</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;`</span>
  <span class="p">}</span>
</pre></div>
</figure>
<h3>this and @</h3>
<p>coffee 用 <code>@</code> 代表 this，但小心不要在 jsx 語法裡頭用 <code>@</code>，因為被 <code>``</code>包住的部分會被當成 javascript 來處理，coffeeify不會去處理這部分。舉例來說。</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">HelloMessage</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="na">createClass</span><span class="p">(</span>
  <span class="na">onClick</span><span class="o">:</span> <span class="o">-&gt;</span>
    <span class="nx">alert</span> <span class="s">'onClick'</span>
  <span class="na">render</span><span class="o">:</span> <span class="p">()</span><span class="o">-&gt;</span>
    <span class="o">`&lt;</span><span class="nx">div</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="vi">@</span><span class="na">onClick</span><span class="p">}</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="p">{</span><span class="vi">@</span><span class="na">props</span><span class="p">.</span><span class="na">name</span><span class="p">}</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;`</span>
  <span class="p">}</span>
</pre></div>
</figure>

<p>如此<code>@onClick</code> 就會變成 undefined。應該要改成 <code>this.onClick</code> 來處理。像這樣：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">HelloMessage</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="na">createClass</span><span class="p">(</span>
  <span class="na">onClick</span><span class="o">:</span> <span class="o">-&gt;</span>
    <span class="nx">alert</span> <span class="s">'onClick'</span>
  <span class="na">render</span><span class="o">:</span> <span class="p">()</span><span class="o">-&gt;</span>
    <span class="o">`&lt;</span><span class="nx">div</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="na">onClick</span><span class="p">}</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="na">props</span><span class="p">.</span><span class="na">name</span><span class="p">}</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;`</span>
  <span class="p">}</span>
</pre></div>
</figure>
<h3>every component need a root parent</h3>
<p>每一個 component 都需要一個 parent 來包住，例如你不能這樣寫 jsx：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">HelloMessage</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="na">createClass</span><span class="p">(</span>
  <span class="na">render</span><span class="o">:</span> <span class="p">()</span><span class="o">-&gt;</span>
    <span class="o">`&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="nx">foo</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;</span>
    <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="nx">bar</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;</span>
    <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="nx">foobar</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;`</span>
  <span class="p">}</span>
</pre></div>
</figure>

<p>而是要用一個 element 包住：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">HelloMessage</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="na">createClass</span><span class="p">(</span>
  <span class="na">render</span><span class="o">:</span> <span class="p">()</span><span class="o">-&gt;</span>
    <span class="o">`&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
      <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="nx">foo</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;</span>
      <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="nx">bar</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;</span>
      <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="nx">Hello</span> <span class="nx">foobar</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;</span>
    <span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;`</span>
  <span class="p">}</span>
</pre></div>
</figure>

<p>由於這可能會影響 HTML 的結構，需要跟 Designer 確定一些實做細節。</p>
<h3>Empty text node will wrap by &lt;span&gt;</h3>
<p>例如</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="o">`&lt;</span><span class="nx">th</span><span class="o">&gt;</span><span class="nx">type</span><span class="p">{</span><span class="nx">foo</span><span class="p">}</span><span class="o">&lt;/</span><span class="nx">th</span><span class="o">&gt;`</span>
</pre></div>
</figure>

<p>會變成這樣<br>
<img src="http://user-image.logdown.io/user/96/blog/96/post/218106/vIaQ5Es4Sp2eggrvn4ER_%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202014-08-09%20%E4%B8%8B%E5%8D%884.18.25.png" style="width:600px;"></p>

<p>這可能會跟原本預期的不太一樣，為了避免樣式問題，可能要跟 Designer 確認避免產生空的文字節點。</p>
<h3>Sperate component if there's any logic control</h3>
<p>用了 jsx 之後會發現遇到邏輯部分的程式會不太好寫。例如用 js/coffee 來寫的話會像是這樣。</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">HelloMessage</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="na">createClass</span><span class="p">(</span>
  <span class="na">render</span><span class="o">:</span> <span class="p">()</span><span class="o">-&gt;</span>
    <span class="nx">R</span><span class="p">.</span><span class="na">div</span> <span class="nx">className</span><span class="o">=</span><span class="s">"form-component"</span>
     <span class="k">if</span> <span class="nx">type</span> <span class="o">is</span> <span class="s">'image'</span>
       <span class="nx">R</span><span class="p">.</span><span class="na">img</span> <span class="na">src</span><span class="o">:</span><span class="nx">data</span><span class="p">.</span><span class="na">src</span>
     <span class="k">else</span> <span class="k">if</span> <span class="nx">type</span> <span class="o">is</span> <span class="s">'input'</span>
       <span class="k">if</span> <span class="nx">inputType</span> <span class="o">is</span> <span class="s">'text'</span>
         <span class="nx">R</span><span class="p">.</span><span class="na">input</span> <span class="na">type</span><span class="o">:</span><span class="s">"text"</span>
       <span class="k">else</span> <span class="k">if</span> <span class="nx">inputType</span> <span class="o">is</span> <span class="s">'radio'</span>
         <span class="nx">R</span><span class="p">.</span><span class="na">input</span> <span class="na">type</span><span class="o">:</span><span class="s">"radio"</span>
    <span class="err">#</span><span class="p">...(</span><span class="nx">skip</span><span class="p">)</span>
</pre></div>
</figure>

<p>而用 jsx 要在一個 render function 做這些判斷會看起來很可怕。建議盡量拆 component，拆 component 是不用錢的。由於 component 都是單一物件的設計，所以盡可能的將一個 component 的邏輯簡化。如上例，可以將裡頭的 if-else 判斷拆出去 <code>FormItem</code>，像這樣：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">FormItem</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="na">createClass</span>
  <span class="na">render</span><span class="o">:</span> <span class="o">-&gt;</span>
    <span class="nx">data</span> <span class="o">=</span> <span class="vi">@</span><span class="na">props</span><span class="p">.</span><span class="na">data</span>
    <span class="k">if</span> <span class="nx">data</span><span class="p">.</span><span class="na">type</span> <span class="o">is</span> <span class="s">'image'</span>
       <span class="o">`&lt;</span><span class="nx">img</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">data</span><span class="p">.</span><span class="na">src</span><span class="p">}</span> <span class="o">/&gt;`</span>
    <span class="k">else</span> <span class="k">if</span> <span class="nx">data</span><span class="p">.</span><span class="na">type</span> <span class="o">is</span> <span class="s">'input'</span>
      <span class="k">if</span> <span class="nx">data</span><span class="p">.</span><span class="na">inputType</span> <span class="o">is</span> <span class="s">'text'</span>
        <span class="o">`&lt;</span><span class="nx">input</span> <span class="nx">type</span><span class="o">=</span><span class="s">"text"</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">data</span><span class="p">.</span><span class="na">value</span><span class="p">}</span> <span class="o">/&gt;`</span>
      <span class="k">else</span> <span class="k">if</span> <span class="nx">data</span><span class="p">.</span><span class="na">inputType</span> <span class="o">is</span> <span class="s">'radio'</span>
        <span class="o">`&lt;</span><span class="nx">input</span> <span class="nx">type</span><span class="o">=</span><span class="s">"radio"</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">data</span><span class="p">.</span><span class="na">value</span><span class="p">}</span> <span class="o">/&gt;`</span>
        
<span class="nx">HelloMessage</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="na">createClass</span><span class="p">(</span>
  <span class="na">render</span><span class="o">:</span> <span class="p">()</span><span class="o">-&gt;</span>
    <span class="o">`&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s">"form-component"</span>
      <span class="o">&lt;</span><span class="nx">FormItem</span> <span class="nx">data</span><span class="o">=</span><span class="p">{</span><span class="nx">data</span><span class="p">}</span> <span class="o">/&gt;</span>
     <span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;`</span>
    <span class="err">#</span><span class="p">...(</span><span class="nx">skip</span><span class="p">)</span>
</pre></div>
</figure>

<p>這是一個很簡單的技巧也可以將 component 快速的拆開，不要嘗試在一個 component 裡頭包入太複雜的邏輯判斷。另一個好處是可以針對單一個 component 來做 unit-test。</p>
<h2>false in jsx</h2>
<p>false 在 jsx 裡頭有些不同的意義，在 <a href="http://facebook.github.io/react/tips/false-in-jsx.html" rel="nofollow" target="_blank">http://facebook.github.io/react/tips/false-in-jsx.html</a> 有說明，不過<del>因為很重要所以要講三次</del>。</p>

<p>其中最重要的是 false element</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="o">`&lt;</span><span class="nx">div</span><span class="o">&gt;</span><span class="p">{</span><span class="no">false</span><span class="p">}</span><span class="o">&lt;/</span><span class="nx">div</span><span class="o">&gt;`</span>
</pre></div>
</figure>

<p>這樣會變成 <code>&lt;div&gt;&lt;/div&gt;</code>，成為一個空的節點。在做一些邏輯判斷時還蠻好用的。</p>
<h3>Never modify DOM by yourself</h3>
<p>如果你開始使用 React 了，請戒掉用 jquery 操作 DOM 的「壞習慣」。真的，一開始會很不習慣，例如<code>addClass('loading')</code>太方便了，但是摻雜使用的後果就是很難 debug。建議要做任何 DOM 的操作都交給 state/props 來決定。</p>

<p>如果有其他使用 React 的小技巧也歡迎分享喔～</p>


              
            

            
          </div>

          

        </article>

        

      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2014/08/05/reactjs-jsx-or-coffee-style">
                
                  [ReactJS] jsx or coffee style
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <h2>JSX</h2>
<p>在寫 ReactJS 時，官方建議使用 <a href="http://facebook.github.io/react/docs/jsx-in-depth.html">jsx</a> 這樣的語法來處理 html，這有點像是 template engine，不知道什麼是 jsx 的同學可以在 <a href="http://facebook.github.io/react/jsx-compiler.html">jsx compiler</a> 玩玩看。jsx 其實不是必要的東西，如果你開心的話也可以直接用 <code>React.DOM.div</code>來撰寫，實際在使用時，對 jsx 充滿了疑惑，要做一些邏輯性的操作(例如 if-else, foo-loop)等等，相對的有點麻煩。</p>

<p>後來看到了一篇文章，推薦用 coffeescript 的特性來直接撰寫 React component：<a href="http://neugierig.org/software/blog/2014/02/react-jsx-coffeescript.html">React, JSX, and CoffeeScript</a>。文章提到用 coffeescript 的特性來操作 component 會更加的得心應手，於是我也動手把 component 直接改成 coffee style。寫出來的程式大概長成這樣：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre>  <span class="nx">R</span><span class="p">.</span><span class="na">div</span> <span class="na">id</span><span class="o">:</span> <span class="s">'list-view'</span><span class="p">,</span> <span class="na">className</span><span class="o">:</span> <span class="s">'view tab-pane fade in active'</span><span class="p">,</span>
    <span class="k">if</span> <span class="nx">listType</span> <span class="o">is</span> <span class="s">'foo'</span>
        <span class="nx">R</span><span class="p">.</span><span class="na">div</span> <span class="na">className</span><span class="o">:</span> <span class="s">'back'</span><span class="p">,</span> <span class="s">'←'</span>
            <span class="nx">R</span><span class="p">.</span><span class="na">p</span> <span class="na">className</span><span class="o">:</span> <span class="s">'alert alert-warning'</span><span class="p">,</span>
            <span class="nx">R</span><span class="p">.</span><span class="na">i</span> <span class="na">className</span><span class="o">:</span> <span class="s">'fa fa-exclamation-circle'</span>
    <span class="k">if</span> <span class="nx">listType</span> <span class="o">is</span> <span class="s">'bar'</span>
        <span class="nx">R</span><span class="p">.</span><span class="na">span</span> <span class="no">null</span><span class="p">,</span> <span class="s">'Hello world'</span>
    <span class="k">else</span>
        <span class="nx">R</span><span class="p">.</span><span class="na">span</span> <span class="no">null</span><span class="p">,</span> <span class="s">'Magic!'</span>
</pre></div>
</figure>
<h4>優點</h4>
<h5>利用縮排來 beautify 程式</h5>
<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">R</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="na">DOM</span>
<span class="nx">R</span><span class="p">.</span><span class="na">p</span> <span class="no">null</span><span class="p">,</span>
    <span class="nx">R</span><span class="p">.</span><span class="na">a</span> <span class="na">href</span><span class="o">:</span><span class="s">'foo'</span><span class="p">,</span> <span class="s">'bar'</span>  <span class="c1"># note omitted comma here
</span>    <span class="nx">R</span><span class="p">.</span><span class="na">a</span> <span class="na">href</span><span class="o">:</span><span class="s">'foo2'</span><span class="p">,</span> <span class="na">rel</span><span class="o">:</span><span class="s">'nofollow'</span><span class="p">,</span> <span class="s">'second link'</span>
</pre></div>
</figure>
<h4>利用 foo-loop 來產生 template</h4>
<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">R</span><span class="p">.</span><span class="na">ol</span> <span class="no">null</span><span class="p">,</span>
  <span class="k">for</span> <span class="nx">result</span> <span class="k">in</span> <span class="vi">@</span><span class="na">results</span>
    <span class="nx">R</span><span class="p">.</span><span class="na">li</span> <span class="na">key</span><span class="o">:</span><span class="nx">result</span><span class="p">.</span><span class="na">id</span><span class="p">,</span> <span class="nx">result</span><span class="p">.</span><span class="na">text</span>
</pre></div>
</figure>

<p>相比之下用 jsx 就囉唆許多：<a href="http://facebook.github.io/react/docs/multiple-components.html" rel="nofollow" target="_blank">http://facebook.github.io/react/docs/multiple-components.html</a></p>
<h4>寫 if-else 像是在喝水的簡單</h4>
<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre>  <span class="k">if</span> <span class="o">not</span> <span class="vi">@</span><span class="na">state</span><span class="p">.</span><span class="na">editing</span>
    <span class="nx">R</span><span class="p">.</span><span class="na">div</span> <span class="no">null</span><span class="p">,</span>
      <span class="vi">@</span><span class="na">props</span><span class="p">.</span><span class="na">text</span>
      <span class="s">' '</span> 
      <span class="nx">R</span><span class="p">.</span><span class="na">span</span> <span class="na">className</span><span class="o">:</span><span class="s">'link-button mini-button'</span><span class="p">,</span> <span class="na">onClick</span><span class="o">:</span><span class="vi">@</span><span class="na">edit</span><span class="p">,</span> <span class="s">'change'</span>
  <span class="k">else</span>
    <span class="nx">R</span><span class="p">.</span><span class="na">div</span> <span class="na">style</span><span class="o">:</span><span class="p">{</span><span class="na">position</span><span class="o">:</span><span class="s">'relative'</span><span class="p">},</span>
      <span class="nx">R</span><span class="p">.</span><span class="na">input</span>
        <span class="na">style</span><span class="o">:</span><span class="p">{</span><span class="na">position</span><span class="o">:</span><span class="s">'absolute'</span><span class="p">,</span> <span class="na">top</span><span class="o">:-</span><span class="mi">16</span><span class="p">,</span> <span class="na">left</span><span class="o">:-</span><span class="mi">7</span><span class="p">}</span>
        <span class="na">type</span><span class="o">:</span><span class="s">'text'</span><span class="p">,</span> <span class="na">ref</span><span class="o">:</span><span class="s">'text'</span><span class="p">,</span> <span class="na">defaultValue</span><span class="o">:</span><span class="vi">@</span><span class="na">props</span><span class="p">.</span><span class="na">text</span>
        <span class="na">onKeyUp</span><span class="o">:</span><span class="vi">@</span><span class="na">onKey</span><span class="p">,</span> <span class="na">onBlur</span><span class="o">:</span><span class="vi">@</span><span class="na">finishEdit</span>
</pre></div>
</figure>
 

<p>相比之下 jsx 的 if-else 限制很多：<a href="http://facebook.github.io/react/tips/if-else-in-JSX.html" rel="nofollow" target="_blank">http://facebook.github.io/react/tips/if-else-in-JSX.html</a></p>
<h4>缺點</h4>
<p>但是一直到最近我放棄了，所以我來說說 coffee style 的缺點。</p>
<h5>無法使用在太複雜的 DOM 結構</h5>
<p>其實可想而知，若DOM結構複雜的話，這樣做會搞死自己，雖然我們自以為對 javascript/coffee 非常熟稔，但人眼終究敵不過 template 的複雜度。這是一段我曾經寫的 component 的程式，坦白說這個結構沒有很複雜，但我看第二次的時候我自己都想殺了我自己，大家可以笑笑：</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">R</span><span class="p">.</span><span class="na">fieldset</span><span class="p">(</span><span class="na">className</span><span class="o">:</span><span class="s">"form-group </span><span class="si">#{</span><span class="nx">ex_className</span><span class="si">}</span><span class="s">"</span><span class="p">,</span>
  <span class="nx">R</span><span class="p">.</span><span class="na">legend</span><span class="p">(</span> <span class="p">{</span><span class="na">className</span><span class="o">:</span><span class="s">"scheduler-border"</span><span class="p">},</span> <span class="nx">item</span><span class="p">.</span><span class="na">name</span><span class="p">),</span>
  <span class="nx">R</span><span class="p">.</span><span class="na">div</span><span class="p">(</span> <span class="p">{</span><span class="na">className</span><span class="o">:</span><span class="s">"table-responsive"</span><span class="p">},</span>
    <span class="nx">R</span><span class="p">.</span><span class="na">table</span><span class="p">(</span> <span class="p">{</span><span class="na">className</span><span class="o">:</span><span class="s">"table table-hover"</span><span class="p">},</span>
      <span class="nx">R</span><span class="p">.</span><span class="na">tbody</span><span class="p">(</span><span class="no">null</span><span class="p">,</span>
        <span class="k">for</span> <span class="nx">d_items</span><span class="p">,</span> <span class="nx">key</span> <span class="k">in</span>  <span class="nx">item</span><span class="p">.</span><span class="na">dynamic_item</span>
          <span class="nx">console</span><span class="p">.</span><span class="na">log</span> <span class="nx">d_items</span>
          <span class="nx">R</span><span class="p">.</span><span class="na">tr</span><span class="p">(</span><span class="no">null</span><span class="p">,</span>
            <span class="k">for</span> <span class="nx">i</span> <span class="k">of</span>  <span class="nx">d_items</span>
              <span class="nx">d_item</span> <span class="o">=</span> <span class="nx">d_items</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span>
              <span class="k">if</span> <span class="nx">d_item</span><span class="p">.</span><span class="na">type</span> <span class="o">is</span> <span class="s">'dropdown'</span>
                <span class="nx">R</span><span class="p">.</span><span class="na">td</span><span class="p">(</span><span class="no">null</span><span class="p">,</span>  <span class="nx">DropdownItem</span><span class="p">(</span><span class="na">item</span><span class="o">:</span><span class="nx">d_item</span><span class="p">))</span>
              <span class="k">else</span>
                <span class="nx">R</span><span class="p">.</span><span class="na">td</span><span class="p">(</span><span class="no">null</span><span class="p">,</span>  <span class="nx">TextItem</span><span class="p">(</span> <span class="na">item</span><span class="o">:</span> <span class="nx">d_item</span><span class="p">))</span>
            <span class="nx">R</span><span class="p">.</span><span class="na">td</span><span class="p">(</span><span class="no">null</span><span class="p">,</span>
              <span class="nx">R</span><span class="p">.</span><span class="na">button</span><span class="p">(</span> <span class="p">{</span><span class="na">type</span><span class="o">:</span><span class="s">"button"</span><span class="p">,</span><span class="na">className</span><span class="o">:</span><span class="s">"btn btn-default btn-sm"</span><span class="p">,</span>
              <span class="na">onClick</span><span class="o">:</span> <span class="nx">do</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span><span class="o">=&gt;</span>
                <span class="o">=&gt;</span> <span class="vi">@</span><span class="na">removeItem</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span>
              <span class="p">},</span>
                <span class="nx">R</span><span class="p">.</span><span class="na">i</span><span class="p">(</span> <span class="p">{</span><span class="na">className</span><span class="o">:</span><span class="s">"glyphicon glyphicon-remove"</span><span class="p">})</span>
              <span class="p">)</span>
            <span class="p">)</span>
          <span class="p">)</span>
      <span class="p">)</span>
    <span class="p">),</span>
    <span class="nx">R</span><span class="p">.</span><span class="na">div</span><span class="p">(</span><span class="no">null</span><span class="p">,</span>
      <span class="nx">R</span><span class="p">.</span><span class="na">button</span><span class="p">(</span> <span class="p">{</span>
        <span class="na">type</span><span class="o">:</span><span class="s">"button"</span>
        <span class="na">className</span><span class="o">:</span><span class="s">"btn btn-info btn-xs extend form-add"</span>
        <span class="na">onClick</span><span class="o">:</span> <span class="vi">@</span><span class="na">addItem</span>
      <span class="p">},</span>
      <span class="nx">R</span><span class="p">.</span><span class="na">i</span><span class="p">(</span> <span class="p">{</span><span class="na">className</span><span class="o">:</span><span class="s">"glyphicon glyphicon-plus"</span><span class="p">})</span>
      <span class="p">)</span>
    <span class="p">)</span>
  <span class="p">)</span>
<span class="p">)</span>
</pre></div>
</figure>
<h5>難以維護</h5>
<p>由於 coffee 終究是 javascript，用 coffee 來寫基本上就只是在寫程式，一開始我對於可以使用 underscore 之類的 library 來寫 react component 感到很興奮，最後發現這根本沒辦法維護。比方說，我們可以這樣用</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">React</span><span class="p">.</span><span class="na">DOM</span><span class="p">.</span><span class="na">div</span> <span class="no">null</span><span class="p">,</span> <span class="nx">foo</span><span class="p">.</span><span class="na">bar</span><span class="p">.</span><span class="na">map</span><span class="p">(</span> <span class="p">(</span><span class="nx">r</span><span class="p">)</span><span class="o">-&gt;</span> <span class="nx">fruit</span><span class="p">[</span><span class="nx">r</span><span class="p">]).</span><span class="na">join</span><span class="p">(</span><span class="s">', '</span><span class="p">)</span>
</pre></div>
</figure>

<p>看起來很簡單，而且寫起來很乾淨，但是當 template 摻雜著太多的邏輯，可就不好玩了，因為你很難控制團隊中大家會怎麼去使用這些東西，其實 template 應該還是回歸單純，只能接收 data，顯示 data。邏輯等等的東西應該都不要跟 template 有太多瓜葛。</p>
<h3>結論</h3>
<p>在經過一段時間的實做之後，我認為這些缺點非常致命，因此我不建議使用 coffee 來寫 react component，雖然說官方也提到 jsx 不是必要，但若是團隊合作的專案之中，建議還是乖乖的使用 jsx 來處理 template，盡量將邏輯與 template 分開。</p>

<p>下次會分享一些使用 jsx 的小技巧。</p>


              
            

            
          </div>

          

        </article>

        

      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2014/07/29/express-api-proxy-config">
                
                  [expressjs] request proxy
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <h2>api proxy</h2>
<p>最近使用 expressjs 要將 api proxy 到另外一個 domain 的 api server 上。查了一下最簡單的做法是用 <a href="https://github.com/mikeal/request">request</a> 來處理。</p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="kd">var</span> <span class="nx">API_HOST</span> <span class="o">=</span> <span class="s1">'xxx.com'</span><span class="p">;</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="s1">'/proxy'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">request_params</span><span class="p">,</span> <span class="nx">url</span><span class="p">;</span>
  <span class="nx">url</span> <span class="o">=</span> <span class="s1">'http://'</span> <span class="o">+</span> <span class="nx">API_HOST</span> <span class="o">+</span> <span class="nx">req</span><span class="p">.</span><span class="nx">url</span><span class="p">;</span>
  <span class="nx">request_params</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">followAllRedirects</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>  <span class="c1">//redirect if 301~400
</span>
    <span class="na">body</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">)</span> <span class="c1">//POST/PUT/DELETE data 
</span>
  <span class="p">};</span>
  <span class="k">return</span> <span class="nx">req</span><span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">request</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">request_params</span><span class="p">)).</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">res</span><span class="p">);</span>
<span class="p">});</span>
</pre></div>
</figure>

<p>看起來很簡單不過為了要解決 api server 會做 301/302 redirect 的動作，追了<a href="https://github.com/mikeal/request/blob/master/request.js#L799">sourcecode</a>才知道有這個 <code>followAllRedirects</code> 的設定，特此記錄一下。</p>
<h4>reference:</h4>
<ul>
<li><a href="http://stackoverflow.com/a/20539239/797411" rel="nofollow" target="_blank">http://stackoverflow.com/a/20539239/797411</a></li>
</ul>


              
            

            
          </div>

          

        </article>

        

      
        <article class="blog-post" role="article">
          <div class="post-header">
            <h2 class="post-title">
              <a href="http://blackbing.logdown.com/post/2014/07/15/phantomjs-function-prototype-bind">
                
                  [PhantomJS] Function.prototype.bind
                

                
              </a>
            </h2>
          </div>
          <div class="post-content">
            

            
              <h2>PhantomJS 1.9.7 (Mac OS X) ERROR</h2>
<p>使用 reactjs 來寫 test case 時，用 PhantomJS 執行時就遇到這個 error，奇怪的是用其他的 browser 來執行就沒有問題。</p>

<figure class="figure-code code"><div class="highlight"><pre>TypeError: 'undefined' is not a function (evaluating 'RegExp.prototype.test.bind(
      /^(data|aria)-[a-z_][a-z\d_.\-]*$/
    )')
</pre></div>
</figure>

<p>查了一下追到這個 issue <a href="https://github.com/ariya/phantomjs/issues/10522">Function.prototype.bind is undefined</a>，看起來是 PhantomJS 的內核沒有支援 Function.prototype.bind。於是再找到 MDN 的 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">Function.prototype.bind</a>，在載入 reactJS 之前先將這個 polyfill 加進去就可以解決了。</p>
<h5>karma.conf.js</h5>
<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="nx">files</span><span class="err">:</span> <span class="p">[</span>
    <span class="s1">'test/polyfill/*.js'</span><span class="p">,</span>
    <span class="s1">'app/bower_components/react/react-with-addons.js'</span><span class="p">,</span>
    <span class="s1">'.tmp/test/spec/*.js'</span>
<span class="p">]</span>
</pre></div>
</figure>
<h5>phantom_bind_polyfill.js(2014/8/3 updated)</h5>
<p>use <a href="https://github.com/facebook/react/blob/master/src/test/phantomjs-shims.js">react official polyfill</a></p>

<figure class="figure-code code"><figcaption><span>
</span></figcaption><div class="highlight"><pre><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>

<span class="kd">var</span> <span class="nx">Ap</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">slice</span> <span class="o">=</span> <span class="nx">Ap</span><span class="p">.</span><span class="nx">slice</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">Fp</span> <span class="o">=</span> <span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">;</span>

<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">Fp</span><span class="p">.</span><span class="nx">bind</span><span class="p">)</span> <span class="p">{</span>
  <span class="c1">// PhantomJS doesn't support Function.prototype.bind natively, so
</span>
  <span class="c1">// polyfill it whenever this module is required.
</span>
  <span class="nx">Fp</span><span class="p">.</span><span class="nx">bind</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">func</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">args</span> <span class="o">=</span> <span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>

    <span class="kd">function</span> <span class="nx">bound</span><span class="p">()</span> <span class="p">{</span>
      <span class="kd">var</span> <span class="nx">invokedAsConstructor</span> <span class="o">=</span> <span class="nx">func</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="k">this</span> <span class="k">instanceof</span> <span class="nx">func</span><span class="p">);</span>
      <span class="k">return</span> <span class="nx">func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span>
        <span class="c1">// Ignore the context parameter when invoking the bound function
</span>
        <span class="c1">// as a constructor. Note that this includes not only constructor
</span>
        <span class="c1">// invocations using the new keyword but also calls to base class
</span>
        <span class="c1">// constructors such as BaseClass.call(this, ...) or super(...).
</span>
        <span class="o">!</span><span class="nx">invokedAsConstructor</span> <span class="o">&amp;&amp;</span> <span class="nx">context</span> <span class="o">||</span> <span class="k">this</span><span class="p">,</span>
        <span class="nx">args</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">))</span>
      <span class="p">);</span>
    <span class="p">}</span>

    <span class="c1">// The bound function must share the .prototype of the unbound
</span>
    <span class="c1">// function so that any object created by one constructor will count
</span>
    <span class="c1">// as an instance of both constructors.
</span>
    <span class="nx">bound</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="nx">func</span><span class="p">.</span><span class="nx">prototype</span><span class="p">;</span>

    <span class="k">return</span> <span class="nx">bound</span><span class="p">;</span>
  <span class="p">};</span>
<span class="p">}</span>

<span class="p">})();</span>
</pre></div>
</figure>


              
            

            
          </div>

          

        </article>

        

      

      
        <div class="group pagination">
          

          <a class="archive" href="http://blackbing.logdown.com/archives">Blog Archives</a>

          
            <a class="prev" href="?page=2">← Older</a>
          
        </div>
      
    </div>

    <div class="site-footer">
      <footer>
        <p>
          © 2013 blackbing.
          <span class="powered-by">
            Powered by <a href="http://logdown.com/">Logdown</a>.
          </span>
          <span class="theme-credit">
            Theme Frankies by <a href="http://about.me/zhusee">Zhusee</a>.
          </span>
        </p>
      </footer>
    </div>
  </div>

  <script src="http://cdn-theme.logdown.io/utils/javascripts/logdown_blog.js"></script>

<iframe src="http://logdown.com/pages/top_controls" width="81" height="26" frameborder="0" scrolling="no" style="position: fixed; z-index: 2147483647; border: 0px; background-color: transparent; overflow: hidden; top: 0px; right: 0px;"></iframe>




<div id="fb-root"></div>
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) {return;}
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=146125455579724";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>


<script type="text/x-mathjax-config">
   MathJax.Hub.Config({
    extensions: ["jsMath2jax.js"]
  });
</script>
<script src="http://mathjax.logdown.io/MathJax.js?config=TeX-AMS_HTML"></script>


  <script type="text/javascript">
  (function() {
    var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
    po.src = 'https://apis.google.com/js/plusone.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
  })();
</script>



  <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>





<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
disqus_shortname = 'blackbing'; // required: replace example with your forum shortname

/* * * DON'T EDIT BELOW THIS LINE * * */
(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>



<!-- Start Alexa Certify Javascript -->
<script type="text/javascript">
_atrk_opts = { atrk_acct:"KOI0g1aYS500G0", domain:"logdown.com",dynamic: true};
(function() { var as = document.createElement('script'); as.type = 'text/javascript'; as.async = true; as.src = "https://d31qbv1cthcecs.cloudfront.net/atrk.js"; var s = document.getElementsByTagName('script')[0];s.parentNode.insertBefore(as, s); })();
</script>
<noscript><img src="https://d5nxst8fruw4z.cloudfront.net/atrk.gif?account=KOI0g1aYS500G0" style="display:none" height="1" width="1" alt=""></noscript>
<!-- End Alexa Certify Javascript -->
</body>
</html>
