# React : log-01 ###### tags: `Log` ## 2021.1.26 1. JSX的部分應該是負責MVC中的view和C接受使用者請求的部分。 2. JSX是immutable的,這可以解釋所有的react渲染方法。 3. React可以動態渲染的原因是因為lifecycle。 ## 2021.2.25 : LifeCycle before mount ### 前言 - 理解重點 : 1. 功用。 2. 可以讀state?(JS object建立了沒?)。 3. 可以讀props?(JS object建立了沒?)。 4. 可以用setState?(全部都要建立,才可以觸發updateLifeCycle)。 - 原因 : 時間點為在還沒有mount上之前,所以我們應該注意的是。 1. Virtual DOM建立了沒。 2. DOM建立了沒。 3. JS object建立了沒。 ### 一 . 流程 - ```constrouctor ``` - ```getDerivedStateFromProps``` - ```render ``` - ```DOM build``` - ```componentDidMount``` (可以設為async) ### 二 . constrouctor - 功用 : 初始化state和bind方法。 1. 參數 : 只有一個props。 2. 回傳 : 沒有。 - 不能使用setState。 - 可以讀取props的資料,但如果state會和props有關的化,不應在這裡處理。 ### 三 . getDerivedStateFromProps - 功用 : 根據props改變state的內容。 1. 傳入兩個參數 : ```props state```,表示初始完的。 2. 必須回傳一個物件 : 為新增的state內容,或改變的內容,沒有的化回傳null。 - 不可以使用setState : 是static的函式。 - 可以讀取props和state,用參數傳入。 ### 四 . render - 功用 : 生成新的virtual DOM。 1. 參數 : 沒有。 2. 回傳 : 沒有。 - 不應在這裡使用setState,因為render的過程應該是所有改變都完成時。 - 可以讀取state和props。 ### 五 . componentDidMount - 功用 : 第一次fetch data,或其他在第一次component出現需要其他事,不屬於前面的,都可以放這。 1. 參數 : 沒有。 2. 回傳 : 沒有。 - 可以用setState : 可以將fetch到的資料,更新component。 - 可以讀取state和props。 - 補充說明 : react的設計是希望fetch初始化資料的部分,用update的資料週期。 1. 所以會多設一個變數,讓畫面在沒fetch到資料時,呈現loading的樣子。 2. 換句話說,先初始化成load的畫面,在fetch data,用setState觸發upadte的週期。 ```javascript= async componetDidUpdate(){ let data = await fetch(); ...... setState({....}) } ``` ## 2021.2.26 : LifeCycle when update ### 一 . 流程 - setState()或是props改變。 - ```getDerivedStateFromProps```。 - ```shouldComponentUpadte```。 - ```rednder```。 - ```getSnapShotBeforeUpdate```。 - ```DOM build```。 - ```cmomponentDidUpdate```。(可以設為async) ### 二 . setState和state的改變 - state可以不用經過setState改變。 1. 可以用JS的pass by sharing的特性,改變state的object內容。 2. 但用非setState的方法,不會主動觸發lifeCycle,可能沒有重新渲染畫面。 ```javascript= handlerButton(){ let obj = this.state.obj; obj.text = 'change'; } render(){ return ( <p>{this.state.obj.text}</p> ) } ``` - 避免使用外部identifer改變內部state : 1. 看起來好像可以 : 先上車後補票的概念。 1. 不適合 : 原因除了上面的,還有在下一個生命週期時的問題 ```javascript= // Component state ={ obj :{ name : 'steven' } } // 應該這樣 handler(){ this.setState({ obj :{ ... this.state.obj id : 100 } }) } // 錯誤 handler(){ let tmp_obj = this.state.obj; obj.id='100'; this.setState({ obj : tmp_obj }) } ``` ### 三 . getDerivedStateFromProps : 同mount的生命週期 - 功用 : 根據props改變state的內容。 1. 傳入兩個參數 : ```props state```,表示初始完的。 2. 必須回傳一個物件 : 為新增的state內容,或改變的內容,沒有的化回傳null。 - 不可以使用setState : 是static的函式。 - 可以讀取props和state,用參數傳入。 ### 四 . shouldComponentUpdate - 功用 : 需不需要呼叫render生成新的vitrual DOM 1. react的預設 : 只要setState或props變化,就會進入update lifecycle, 2. 使用時機 : 改變的state或props內容不會影響view層,就可以不要呼叫render函式,也不會進行之後的函式。 4. 傳入參兩個數 : ```nextState, nextProps```,代表下一個階段的state和props。 5. 必須回傳布林值 : 代表需不需要觸發render函式,但不論如何要不呼叫render,此函式後this.state真正改變。 - 可以讀入『未改變的state和props』。 - 補充說明 : 注意這邊obj的比較,是比較address。 1. 一開始setState的寫法,會影響nextState的物件位址。 2. 注意js的物件比較是根據位址,所以不應該單純用『===』比較。 ```javascript= // Component state ={ obj :{ name : 'steven' } } // 情況一 : setState用新的物件 handler(){ this.setState({ obj :{ ... this.state.obj id : 100 } }) } componentDidUpdate(nextState, nextProps){ // 此時的nextState 是一個新的物件 if(nextState === this.state){ return false; } return true; } // 況一 : setState用原本的物件操作 handler(){ let tmp_obj = this.state.obj; obj.id='100'; this.setState({ obj : tmp_obj }) } componentDidUpdate(nextState, nextProps){ // 此時的nextState 是原本的物件 if(nextState === this.state){ return false; } return true; } ``` - 補充說明 : props的更改,即使元件繼承的props部分沒有更改,元件仍會進行update lifeCycle。 1. father被push下,father進入render的週期,會自動更新子元件。 2. 同理,若father沒有進行render,child就不會進行任何的更新,庚變的props也不會傳入child中。 ```javascript= const child = (props)=>{ render (){ return ( <p>{this.props.text}</p> ) } } class Father extends React.Component{ constrouctor(props){ this.state={ text_a : 'aa', text_b : 'bb', } this.handle = this.hanle.bind(this); } handle(){ this.setState({ text_a : 'aaaa' }) } render(){ return( <div> <child text={this.state.text_a}/> <child text={this.state.text_b}/> <button onClick={this.handle}/>push </div> ) } } ``` ### 五 . render - 功用 : 生成新的virtual DOM。 1. 參數 : 沒有。 2. 回傳 : 沒有。 - 不應在這裡使用setState,因為render的過程應該是所有改變都完成時後。 - 可以讀取state和props。 ### 六 . getSnapShotBeforeUpdate - 功用 : DOM tree真正改變前,取得改變前DOM的位置。 1. 參數傳入 : ```(preProps, preState)```。 2. 回傳 : 可有可無,回傳的東西會跑到componentDidUpdate的接收參數。 - 可以讀取state和props。 - 不應在這裡使用setState,此時的時間點應該為virtual DOM和資料更新完。 ### 七 . componentDidUpdate - 功用 : 全部更新後,要執行的事,設計上主要是給因為props改變而需要進行的事情。例如props改便造成state的改變,或props改變需要fetch資料。 1. 參數傳入 : ```(preProps, preState , snapshot)```。 2. 回傳 : 沒有 - 可以讀取state和props。 - 可以在這裡使用setState,如props改變要fetch data後的設定。 1. 但注意,這邊的setState必須要在某個條件內,且不能恆為true。 2. 因為這樣的話可能陷入無窮迴圈。 - 補充說明 : update的fetch data 位置 。 1. handler內 : 代表fetch data這件事在敘述上為『event trigger的』。 2. componentDidUpdate : 代表fetch data 這件事在敘述上為『state或props trigger的』 ```javascript= // in my component async handleButton(){ if(!this.state.data){ let data = await fetchFunction(); this.setState({ state_data : data }); } } render(){ <button onClick={this.handleButton}>fetch data</button> } ``` ```javascript= // in my component handleButton(){ if(!this.state.data){ this.setState({ need_fetch_data : true }); } } async componentDidUpdate(){ if(this.state.need_fetch_data && !this.state.data){ let tmp = await fetchFunction(); this.setState({ data : tmp; }) } } render(){ <button onClick={this.handleButton}>fetch data</button> } ``` ## 2021.3.2 : 一些發現的react心得 ### 第一點 : react的lifeCycle設計,應該是希望你可以『一次改變一個source』的資料。 - react 遵守『single source of turth』。 1. 一個data只能由一個component的life cyle去觸發改變。 2. 如果data有兩個props的來源(應該只出現在route使用時)。 3. 基本上react應該會希望你用兩個lifeCycle觸發改變。 - 例子 : 1. ```<Child>``` : route內部元件。 2. ```<father>``` : route外層container。 ### 第二點 : setState的必須物件必須使用新的物件 - 前面有提到,setState不行用assign的方法。 1. 可以跑的。 2. 但在shouldComponentUpdate時,preState和nextState是同一個物件『address同,內容也同』。 3. 所以,這樣的set up 會讓你『走後門』的改變react的變數。 ```javascript= let bad_ref = this.state.someVar; bad_ref.newAttribute ='text for new'; this.setState({ someVar : bad_ref }); ``` - 所以一定要新建物件,或用map新增一個array。 ```javascript= this.setState({ array : array.map(ele =>{ if(ele.name === nameOfWeWant){ return { ...ele , newAtrribute : 'newStuff' } } return ele; }) }) ``` ## 2021.3.2 : hook base ### 一 . React.memo ( like hook , but is not) 1. 功用 : function component的PureComponent。 - 會shallow檢查function component的props。 - 若沒有變化,則不進行更新。 2. 使用 : 傳入兩個參數。 - function Component : 要變成memo的component。 - equl function : 判斷可以不可以呼叫render。 3. 注意一 : 只比較props,若function component有用hook,則沒辦法比較,需要另外傳入function。 ### 二 . Hight-order-component 1. 功用 : 再次包裝component。 2. 例子 : React.memo。 ### 二 . useState 1. 功用 : 在function中使用component的state。 ### 三 . useEffect