gracekrcx / weekly-notes

4 stars 0 forks source link

[2020-02-11] React - 2 #61

Open gracekrcx opened 4 years ago

gracekrcx commented 4 years ago

Virtual DOM

  1. 使用 DOM diff 這個演算法去比較前後 Virtual DOM 的差異
  2. Virtual DOM 就是一個 javascript 物件,所以就是拿前後兩個 Virtual DOM 物件來比較
  3. key 有利於比較兩個 Virtual DOM 的差異,加快 DOM diff 的效率,所以 key 最好是用唯一值
// 這樣或許就無法比對出 key:1 和 key:2 是有做變動的
[
 { item:1, content:1, key:0 },
 { item:2, content:2, key:1 },
 { item:3, content:3, key:2 },
]

[
 { item:4, content:4, key:0 },
 { item:1, content:1, key:1 },
 { item:2, content:2, key:2 },
 { item:3, content:3, key:3 },
]

Lifecycle

The componentDidMount() method runs after the component output has been rendered to the DOM. This is a good place to set up a timer

componentDidMount() 在第一次 render 之後執行

component 經過 construct 建立,以及經過第一次 render 之後,可以執行一次 componentDidMount(),這時候 DOM tree 已經可以被讀取到

如果你在 constructor 就嘗試去讀取 DOM tree,是會失敗的

componentDidMount() {
 // set up 
 // This is called “mounting” in React.
 // 當 compoment 第一次被建立在 DOM 上之後,可以用這個 method 去做一些事情
 this.timerID = setInterval(
      () => this.tick(),
      1000
    );
}

componentDidUpdate(prevProps, prevState){
 // 很常用:目前狀態和新的狀態不同時,發出反應
 // 會在更新後馬上被呼叫。這個方法並不會在初次 render 時被呼叫。
 // 常見用法(別忘了比較 prop):比較目前的 prop 和之前的 prop 
   if (this.props.userID !== prevProps.userID) {
     this.fetchData(this.props.userID);
   }

   if(prevProps.isLoading === true && this.props.isLoading === false){
     alert('sucess')
   }
}

componentWillUnmount() {
 // component 要從 DOM 上面拿下來
 // 正要離開,做一些清理的動作
 // This is called “unmounting” in React.
 // 當 compoment 要被 removed 時,可以用這個 method 去做一些事情
  clearInterval(this.timerID);
}

Tip:
如果 shouldComponentUpdate() 回傳的值為 false 的話,componentDidUpdate() 將不會被呼叫。

Lifecycle methods

Initialization

Mounting

Updating

Unmounting

在 Updating:props 有 componentWillReceiveProps,state 沒有

Immutable

Immutable 翻成中文就是永遠不變的,意思就是:「當一個資料被創建之後,就永遠不會變了」。如果需要更改資料的話,就創一個新的。

Immutable Data

  1. 很常的情況會用 map, filter, es6 語法去做新增,刪除,修改,去產生一個新的 array 回傳值
  2. 當你要改變一個 state 就要產生一個新的,不能改到舊的,因為要做比對
  3. 直接操作 state 他還是可以跑,但有些優化他就會壞掉
list : [...this.state.list, Math.random()]

(0) list.map((val, index) => index === id ? 123 : val)
(x) list[id] = 123

(0) this.state.list.filter((item, index) => index !== deleteIndex)
(x) splice();

bug 示範

因為 newList 和 list 是相同的記憶體位置,又有 shouldComponentUpdate 在確認需不需要 render ,這時畫面上的操作就會有問題。(如果沒有 shouldComponentUpdate 畫面會正常,但還是建議,在 setState 時要給一個記憶體不一樣的值)(Immutable Data : 當回傳的是一個新的值,才可以有效的去比較新舊的差異)

handleClick = ()=>{
 const newList = this.state.list
 newList.push(Math.random())
 this.setState({
  list : newList  // newList === list => true
 })
}

shouldComponentUpdate(nextProps, nextState){
 if(this.state.list !== nextState.list){ 
   return true  
 }
return false
}

深比較與淺比較

var a ={
 a:1
}
var b ={
 a:1
}

deep comparison : 值一個一個比較,所以結果會是 true 💙💙 shallow comparison : 比較記憶體位置,也就是 ===,所以 a===b 會是 false shallow compare 歸結為兩點:

  1. 採用嚴格相等:
    • 對於基本型別(number, string, boolean, null, undefined, symbol),值必須要完全相等
    • 對於物件型別 (object, array, function),必須指向同一個reference。
  2. 只比到第一層:這也就是 shallow 的含義,第一層的值要嚴格相等,且屬性名稱、數目必須一樣。

shouldComponentUpdate

  1. 決定要不要 call render 這個 function,決定要不要更新 DOM
  2. 官方建議使用 PureComponent
    shouldComponentUpdate(nextProps, nextState){
    return false  
    // 這代表忽略所以的 render 不管什麼 state 被改變
    // 都不 render()
    }
shouldComponentUpdate(nextProps, nextState){
 if(this.state.list !== nextState.list){  // shallow comparison
   return true  
 }
}

把更新 state 和檢查 state 切開來寫,之後比較好維護

可以利用 componentDidUpdate() 來對 state 做一些檢查

componentDidUpdate(){
 if(this.state.num > 5 || this.state.year > 2025) {
  do something
 }
}

Uncontrolled Component

  1. ref(不建議使用類似 document.querySelector 的方法)
  2. React.createRef():react 包好可以存取到 DOM 物件的方法
  3. 為什麼 uncontrol:因為 state 裡面沒有 input 的 value

參考文章

shouldComponentUpdate() 從頭打造一個簡單的 Virtual DOM Day04 - Virtual DOM & V-Node Developing modern offline apps with ReactJS, Redux and Electron ReactJs component lifecycle methods — A deep dive React 效能優化 — PureComponent

gracekrcx commented 4 years ago
const people = { 
  body: {
    height: 50, 
    weight: 120
  }
}
const people2 = people
people2.body.height = 180

people2 === people // true
  1. 第一層屬性名、數量 ---> 相同
  2. object 都指向同一個 reference
gracekrcx commented 4 years ago

shallowCompare

const shallowCompare = require('react-addons-shallow-compare')

const Button = React.createClass({
  shouldComponentUpdate : function( nextProps, nextState ) {
    return shallowCompare(this, nextProps, nextState);
  }
})

後來 React 為了避免開發者在組件中總是要寫這樣一段同樣的代碼,進而推薦使用 React.PureComponent

探索Vue高阶组件

gracekrcx commented 4 years ago

Hook

Hook 是 function,他讓你可以從 function component「hook into」React state 與生命週期。 Hook 擁抱 JavaScript closure

useState()

  1. useState 是一個讓你增加 React state 到 function component 的 Hook

useEffect()

  1. useEffect 可視為 componentDidMount,componentDidUpdate 和 componentWillUnmount 的組合。
  2. 預設之下,React 在每一次 render 之後運行 effect —— 包括第一次 render
  3. 透過使用這個 Hook,你告訴 React 你的 component 需要在 render 後做一些事情。
  4. 如果你想執行一個 effect 並且僅(在 mount 和 unmount 時)將其清除一次,則可以傳遞一個空 array([])作為第二個參數。

提示:通過忽略 Effect 來最佳化效能 這個要求很常見,所以已內建在 useEffect 的 Hook API 中。如果在重新 render 之間某些值沒有改變,你可以讓 React 忽略 effect。為此,請將 array 作為可選的第二個參數傳遞給 useEffect:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 僅在計數更改時才重新執行 effect

useContext()

接收一個 context object(React.createContext 的回傳值)並回傳該 context 目前的值。

Context

Context provides a way to pass data through the component tree without having to pass props down manually at every level. 提供 pass data through the component tree 不需要一層一層用 props 傳

React.createContext()

  1. Creates a Context object.

Context.Provider

  1. Context.Provider 中的 value 屬性,負責 pass state 的改變
  2. 包含 state 與 function
  3. 似 reducer

Context.Consumer

  1. 在 component 裡需要使用 Context 裡的值時,可以透過 Context.Consumer,其內部需要帶入 function
  2. Requires a function as a child. The function receives the current context value and returns a React node
  3. 之前的經驗是包在 component 最外層,也就是跟這個 component 最相關的 Context,那如果要拿別的 context 的資料,可以使用 useContext()
gracekrcx commented 4 years ago

How does shallow compare work in react

Shallow compare

When comparing scalar values (numbers, strings)

it compares their values.

When comparing objects,

it does not compare their attributes - only their 『references』 are compared

gracekrcx commented 2 years ago

Hook 的規則

只在最上層呼叫 Hook

不要在 loop、 Conditions 或是巢狀的 function 內呼叫 Hook。

只在 React Function 中呼叫 Hook

別在一般的 JavaScript function 中呼叫 Hook。

gracekrcx commented 2 years ago

Array.prototype.filter()

The filter() method creates a shallow copy of a portion of a given array

Shallow copy