2016年10月10日 星期一

學習心得1

人的精神層面的各種能力是有限量的

耐心、思維力、理解力等等皆同

因為大腦連續接收處理相同性質的資訊是會疲乏的,應該均衡利用各部位

理解這個道理,妥善安排並充分利用各種能力,就能進步的很快

例如連續閱讀需要消化的程式相關知識,其實每天都有一個額度,超過了就事倍功半

比較以下兩種分配兩個工作天的方式:

a方式:
連續一整天閱讀react相關學習資源
連續一整天畫設計圖

b方式:
半天閱讀、半天畫圖
半天閱讀、半天畫圖

我認為b方式是比較高效率的

2016年10月8日 星期六

lifecycle methods 重點

1、lifecycle methods(下稱lm)是指在元件的生命周期中的特定時間點被呼叫的methods

你可以寫一個lm在一個元件第1次render之前呼叫


你可以寫一個lm在一個元件每次render之後呼叫,除了第1次render


你可以在元件的生命周期中的諸多不同時機點執行lm


2、lm有3種類別:

mounting、updating、unmounting

mounting monent:


元件在它首次render時掛載(mounts),這也是mounting類別的lm執行的時機點


mounting lm有3種:

componentWillMount//在render之前執行(html元素載入之前)
render(載入html元素)
componentDidMount//在render之後執行(html元素載入之後)

當元件掛載時依序執行這3個lm

除了render(同時屬於updating類別),另外兩個只在首次render時執行 


componentDidMount(下稱cdm)在render之後執行,如果你用ajax來取得初始資料,則cdm很適合用來執行這個工作,它也適合用來連結外部應用,例如web api或是js framework,也很適合用它來設定timers,使用setTimeout或setInterval


updating moment:


元件在首次render時沒有update,元件在每次render時update,除了第1次,每個元件每次update都會自動執行它的updating lm


updating lm有5種依執行先後順序排列如下:


componetWillRecieveProps(下稱cwrp)


shouldComponentUpdate(scu)


componentWillUpdate(cwu)


render


componentDidUpdate(cdu)


cwrp只有在元件有接收props的情況下會被呼叫,時機點如下例(引用codecademy範例)所示

// componentWillReceiveProps will get called here:

ReactDOM.render(
  <Example prop="myVal" />,
  document.getElementById('app')
);

// componentWillReceiveProps will NOT get called here:

ReactDOM.render(
  <Example />,
  document.getElementById('app')

);


cwrp自動接收一個nextProps參數,這個參數是一個物件,內容和即將傳入的props相同,一般用來事前比對,符合條件才render該prop或是做其他處理


scu在cwrp之後執行,自動接收兩個參數,nextProps, nextState,並回傳true或false,若回傳true則正常update,但若回傳的是false,則不會執行後續的3個updating lm,包含render 。通常用來比對nextProps和this.props以及nextState,thisState,依據結果回傳true or false,判斷是否update


範例: https://codepen.io/anon/pen/wqPxYX?editors=1011


cwu在scu之後執行,同樣自動接收兩個參數nextProps以及nextState,你不能在cwu中呼叫setState

cwu通常用來和react結構之外的物件互動,如果你需要在元件render之前做一些非react的設定,例如檢查window size或是和外部api互動,那麼cwu是一個適合的地方


render觸發ui重渲染,需注意的是即使未從parent component接收任何props,當parent re-render時其所有children component都會觸發render,而有時因為html架構需求,即使不需要從parent接收props,仍會有成為其child的需要,因此有時會需要使用scu判斷是否需要re-render以避免parent更新時child進行不必要的re-render



cdu在rendered html完成載入後執行,並自動接收prevProps, prevState兩個參數,它們參照到update之前的元件props和state,可以用來和"現況"的props還有state比較

cdu通常和cwu一樣是用來和react環境之外的物件互動,例如browser和api,差別只在它是render之後


unmounting moment:


一個元件的unmounting期間發生在元件從dom中移除時,這可以發生在dom rerender,但未包含該元件時,或是使用者導向到其他網頁,或是關閉瀏覽器時


unmounting moment只有一個lm:


componentWillUnmount(cwun)


cwun在元件從dom移除之前被呼叫,因此如果即將被移除的元件曾經設定需要被清理的方法(例如用setInterval設定的timer),那麼該元件的cwun就是適合你清理這些方法的時機和地方



2016年10月7日 星期五

form 重點

1、controlled component(下稱cc) and uncontrolled component(下稱ucc):

cc與ucc是描述元素是否在react控制之下

例如一般情況下 input元素維護自己的狀態,使用者輸入什麼,它就顯示什麼,我們可以透過value屬性在任何時間點向它取值

但當一個input元素是透過react render出來的,並且有賦於它value屬性,而我們又希望能在使用者keyin內容時掌控state並在特定元素上顯示,所以我們會設定一個eventhandler去監控input內容,並呼叫setState方法改變狀態,setState方法會呼叫render方法更新畫面,這時因為我們有賦於value屬性值,在重新render時等同重置內容,此時這個input便不在是自我控制,而是受react控制,所以稱之為cc,cc與ucc是對於react而言

如果我們希望cc的input元素之value值能依使用者輸入而改變,只要將value屬性值與元件的state狀態連結即可,render方法的return內容會是像下列這樣

<input type="text" onChange={handleUserInput} value={this.state.userInput} />

handleUserInput方法中會呼叫setState方法更新元件的userInput狀態

jsx input元素的value值則和userInput狀態連結

如此一來,便將一個input元素轉換為受控的react input元素

或是換個方式說,在react環境下當我們想要設定有value屬性的元素(例如input)的value初始值,同時希望能用setState方法記錄狀態,又希望能正常反映使用者的輸入內容時(否則會在setState呼叫render方法時重置為初始值,無法正常反映輸入內容),就必須這樣操作,像是把它納入react控制,所以稱之為cc,有value屬性的元素不多,有value屬性又有上述需求的元件就更少,所以大部份的元件都是ucc類型

不想轉換為cc但又想設定初始值的方式:
用以下列屬性替代value屬性設定始初值
defaultValue (for input, select元素)
defaultChecked (for checkbox, radio)


2、form的用途是讓使用者輸入資料,一般方式是使用form元素搭配submit元素,在點擊submit時一次性傳送整個form元素裡面的資料

但是在react有很不一樣的處理方式,它是在使用者輸入每一個字元時都傳輸資料(有變化的部份),所以你可以不需要一個submit按鈕,甚至也不需要一個form元素,僅僅只需要一個input元素即可讓使用者提交資 料

當然你還是會使用form元素和submit按鍵,例如在表單輸入過程中即時比對輸入內容與server端資料並做相應的處理,然後使用者按下送出的動作做為一種確認方式,區分"進行中"與"已完成",但在某些情況下,僅僅只需要簡單的input元素即可滿足需求







2016年10月4日 星期二

state 重點

1、和props不同,state不是由外部傳入,然後props一開始就存在,state則需要定義getInitialState方法並傳回一個物件,此物件會成為state物件,未初始化前讀取state是null

2、和props相同,可以在元件class說明物件(instructions)的任何屬性中使用

3、使用setState方法改變state屬性值,可局部改變,未被改變的部份保持原樣

現況
{
    hungry:false,
    mood:'great'
}

改變部份state
this.setState({
  hungry:true
});

改變後

{
   hungry:true,
   mood:'great'//維持原樣
}

4、不能在元件的render function中直接呼叫setState方法,原因如第5點

5、每次呼叫this.setState這個方法改變狀態值後,它都會自動呼叫render方法,以更新畫面

因此如果在render方法裡面直接呼叫它,它又會馬上呼叫render,render又呼叫它…會變成無窮迴圈

6、重置state的方法
在constructor 儲存一個重置用的備份
this.state = {
   a: 1,

   b: 2
};


this.baseState = this.state;

重置時:
this.setState(this.baseState);

這個方式能作用的原因為每次setState,react都是建立一個新的物件讓this.state參照

所以this.baseState和this.state在使用過setState之後就不是參照到到同一個物件了

7、傳入function到this.setState
https://codepen.io/anon/pen/dzMebJ
這個例子的差別在於雖然都是連續呼叫兩次this.setState
但BadCounter是整合後以後來的state做為結果做render,因其參考的this.state.count未變,所以兩次的結果相同,只+1。

GoodCounter以函數接受prevState,兩次呼叫間更新了state的值,但最後才做1次render。


props

1、props:在components(以下稱元件)之間傳遞的資訊

每個元件都有props,它是一個物件,用來存放和元件相關的資訊


傳遞資訊給元件的方式:


文字形態的資訊


<MyComponent anyNameYouLike="你好!" />


非文字形態的資訊都要用'{}'括起來,包含數字也是


<MyComponent info1="你好" info2={['a','b','c']} info3={2} info4={true} />


傳遞進去的資訊會存放在該元件的props物件中


亦可傳遞函數,通常傳遞做為event handler的函數

在react中,函數會定義在元件class的說明物件中

只能在render方法裡面的return內容中傳遞props給其它component instance

對於定義函數與傳遞函數給其他元件的那個元件本身,對於事件監聽函數以及傳遞的prop的名稱是有一個命名慣例存在的,不一定要遵守,但瞭解規則是有好處的


handler的名稱通常是handle+事件名稱,例如handleClick


prop的名稱通常是on+事件名稱,例如onClick


這有點容易搞混,因為jsx元素有兩個類別,一是html-like,一是component instance


在html-like元素中屬性名稱on+事件名稱(首字大寫,如onClick)是用來綁定事件監聽器


但在component instance中屬性名稱on+事件名稱只是一個通常用來傳遞事件監聽器的props屬性名稱


換句話說on+事件名稱(首字大寫)在component instance類別的jsx元素中並沒有特殊功能,並不會有綁定監聽器的動作,它就只是一個隨意的名稱


區分jsx兩種元素類別的方式很簡單,只要記住component instance標籤字首是大寫


component instance通常表示成self-closing標籤,但也可以寫成一般有開頭和結尾的形式,同樣有效,例如<MyComponent></MyComponet>,寫成開頭與結尾的方式有個好處,每個元件的props都有一個children屬性,this.props.children代表在component instance的開頭與結尾標籤中所有元素


<MyCom>

   this is a text.
</MyCom>
this.props.children等於"this is a text."

<MyCom>
<MyCom2 />
</MyCom>
this.props.children等於<MyCom2 />這個元件

要注意當開頭與結尾之間有超過一個以上的元素,則children是array

但當之間只有一個元素的時候,children就是該元素,而不會用array包裝 

被包含在component instance的開頭和結束標籤中的元素不會被render


設定props預設值的方法:


在說明書文件中定義"getDefaultProps"方法,return一個物件,該物件內容會加到props裡面,當有從外部傳遞props屬性時,會以外部傳入的值取代預設值,否則套用預設值

var Button = React.createClass({
  getDefaultProps:function(){
    return {text:'I am a button'};
  },
  render: function () {
    return (
      <button>
        {this.props.text}
      </button>
    );
  }
});

ReactDOM.render(
  <Button />,
  document.getElementById('app')
);

未傳入text prop,所以使用預設值"I am a button"


2、propTypes,props驗證與文件化

用法如下(參考codecademy):
在元件定義物件中新增一個propTypes屬性,值為物件,當一個元件預期接收props,則在此物件中加入對應prop名稱的key,值則需符合"React.PropTypes.指定的形態" 這種格式,其代表接收的指定prop需符合該形態,否則在console會有警告訊息

加上.isRequired表示是必要傳入值,若未傳入,則一樣會在console有警告訊息

一般會將propTypes定義在最上方,可以幫助檢閱這個元件的用途並加上說明

var Runner = React.createClass({
  propTypes: {
    message:   React.PropTypes.string.isRequired,
    style:     React.PropTypes.object.isRequired,
    isMetric:  React.PropTypes.bool.isRequired,
    miles:     React.PropTypes.number.isRequired,
    milesToKM: React.PropTypes.func.isRequired,
    races:     React.PropTypes.array.isRequired
//只有bool和func是簡寫表示,其餘形態都是完整寫法
  },

  render: function () {
  var miles = this.props.miles;
    var km = this.props.milesToKM(miles);
    var races = this.props.races.map(function(race, i){
      return <li key={race + i}>{race}</li>;
    });

    return (
      <div style={this.props.style}>
        <h1>{this.props.message}</h1>
        { this.props.isMetric && 
          <h2>One Time I Ran {km} Kilometers!</h2> }
        { !this.props.isMetric && 
          <h2>One Time I Ran {miles} Miles!</h2> }
        <h3>Races I've Run</h3>
        <ul id="races">{races}</ul>
      </div>
    );
  }

});


react.js 重點

1、引入其他js檔案方式為require,當require內的字串以'.' or '/' 開始時,表示給的是路徑

const Class = require('./Car.js');

若未給定副檔名,預設為".js"
所以也可以寫成這樣

const Class = require('./Car');


2、props與state都是component(元件)用來儲存動態資訊的物件,差異在於:
props儲存的是可由其他元件(除了自己)改變的資訊
state儲存的是可以由元件自身自己改變的資訊


3、在react.js v0.4以後,"this"關鍵字使用在定義component class的instruction物件中的function定義時,自動綁定為該元件,而非在function被呼叫時依owner改變

var MyComponent = React.createClass({
    functionYouDefined: function(){
         console.log(this) //此this綁定為MyComponent instance
    }
});

換個方式說,當this使用在物件的定義上時,行為就是綁定至該物件,使用在一般function時則是依function被呼叫時,其owner為何


4、react 編程模式1(programming pattern):

基本架構:

1個有狀態的父元件負責儲存資訊
1個無狀態的子元件負責顯示狀態內容
1個無狀態的子元件負責更新父元件的狀態
資訊狀態統一由父元件向下傳遞

流程如下:

1、一個有狀態(有getInitialState方法)的a元件定義一個有參數的方法,其內呼叫setState方法使用參數更新a元件的state

2、a元件傳遞這個更新state的方法給另一個無狀態的b元件

3、b元件定義一個可接收事件物件的方法,其內呼叫由a傳入的更新方法,並把事件物件的屬性傳遞進去,以更新a元件的state

4、b元件將可接收事件物件的方法做為事件handler

5、當特定事件觸發,a元件的state更新(例如從下拉式選單選擇一個值)

6、a元件傳遞其更新後state給另一個無狀態元件c

7、c元件接收a元件的state並將值嵌入jsx元素

8、渲染(render)a元件,c元件顯示state值,b元件顯示一個可供改變state值的途徑,例如下拉式選單


5、在react中不同檔案是互相獨立的,除了你require進來的部份,因此你可以有100個檔案,都有一個global變數叫style,它們也可以不互相衝突


6、react 編程模式2:

基本架構:

從表現元件(presentational)中分離容器元件(container)

分離表現邏輯商業邏輯(類似view和controller的概念)

當一個元件必須擁有狀態或是根據傳入的props進行計算,或是其他任何複雜的邏輯處理,那麼它不該再負責render html-like的jsx元素,而是應該render另一個元件,由那個元件負責render html-like的jsx元素的工作

表現元件唯一的工作就是render html-like的jsx元素,如上述,容器元件會render表現元件,再由表現元件render html-like的jsx元素

有狀態的容器元件負責邏輯處理,將處理結果傳遞給無狀態的表現元件負責顯示工作

7、控制state的元件所在階層要適當,太低與太高皆不宜:

太低無法完整控制,會有難以傳遞給平行元件的問題

太高會有不必要的update情況,父元件update(setState時)代表所有子元件都會update(雖然dom不一定會更新,但檢查是會的),當包含的內容太多時,update太頻繁會導致效能低下,反之子元件update時,上層元件並不會update,所以像是控制input內容這種工作,儘量讓底層元件控制狀態






2016年10月2日 星期日

components 重點

1、components 是小型、可重用、負責單一任務的的程式碼塊,通常包含渲染html的功能

2、components 由component class 產生,呼叫 React.createClass() 方法建立一個新的component class,class名稱開頭必須是大寫,這是通用規則,component class不是component,它比較像是一個專門生產component的工廠

const React = require('react');

const MyComponentClass = React.createClass();

createClass方法接受一個參數,此參數必須是一個js物件,這個物件像是一份說明書,告訴component class如何去生產component

這個參數物件通常會有一個render function,這個render function必須要有return陳述式,並通常會是return一個jsx陳述式

建立一個component class
const MyComponentClass = React.createClass({
  render: function () {
    return <h1>Hello world</h1>;
  }
});

使用component class產生components 的方式透過jsx語法,jsx元素可以是html tag或是component instance,js利用名稱開頭大小寫的差異分辨兩者,這就是為何component class名稱必須開頭必須是大寫的原因

使用class產生一個component的方式如下
<MyComponentClass />

每個component instance都會繼承其parent class的"說明書"中的所有屬性和方法,某component class說明書中有render方法傳回一個jsx元素,則所有該class的component instance都有render方法傳回定義好的jsx元素

要呼叫instance的render方法只要把instance丟給DOM 的render方法做為首個參數即可,DOM的render方法會告訴component instance去呼叫它的render方法,然後DOM的render方法會接收其傳回的jsx元素,並將之渲染在畫面上


將component做為DOM render方法的第一個參數傳入

ReactDOM.render(
<MyComponentClass />,
document.getElementById('app')
);

畫面上將會出現h1大小的Hello world


3、stateless functional component:

一個表現型元件通常只有一個render function,沒有其他了,這種類型的元件可以用一種特殊寫法,像寫一般js的function一樣的方式,如下:

// 元件一般定義方式
var MyComponentClass = React.createClass({
  render: function(){
    return <h1>Hello world</h1>;
  }
});

// 同樣的元件,使用無狀態功能型元件寫法:
function MyComponentClass () {
  return <h1>Hello world</h1>;
}

// 不同寫法,一樣的運作結果:
ReactDOM.render(
<MyComponentClass />,
document.getElementById('app')

);

無狀態功能型元件寫法(以下稱sfc寫法)接收props的方式是定義一個參數,習慣上取名為props,這個參數對應到props物件,傳入的prop自動對應到props參數物件的屬性與值

// 一般方式顯示props屬性值:
var MyComponentClass = React.createClass({
  render: function () {
    return <h1>{this.props.title}</h1>;
  }
});

// 無狀態功能型元件顯示props屬性值的方式:
function MyComponentClass (props) {
  return <h1>{props.title}</h1>;
}

// 一般方式使用變數顯示props屬性值的方式:
var MyComponentClass = React.createClass({
  render: function () {
  var title = this.props.title;
    return <h1>{title}</h1>;
  }
});

// 無狀態功能型元件使用變數顯示props屬性值的方式:
function MyComponentClass (props) {
var title = props.title;
  return <h1>{title}</h1>;

}

無狀態的功能型元件寫法除了簡潔,也稍稍的禪示了元件就像function,輸入可選的state與props參數,輸入html或其他元件

為sfc寫法加入propTypes的方法:

function Example (props) {
  return <h1>{props.message}</h1>;
}

Example.propTypes = {
  message: React.PropTypes.string.isRequired
};