在開始進入正式主題前,我們先來談談兩種不同的編程方式 - 命令式編程(imperative programming)與宣告式編程(declaritive programming)。
首先從定義開始:
嗯...有點難以理解,舉個搭計程車的例子。
我們一般都會和計程車司機說我們想要前往的目的地,至於計程車司機要開哪一條路、在哪一個路口轉彎、開得多快多慢等等我們都不需要煩惱,只要交由司機決定就好,但有些人就是比較熱心(?),一路上會提醒司機要走哪一條小路、在哪裡轉彎就不用等紅燈、哪裡有測速照相機要開慢一點等等,告訴司機到底怎麼開才會到達目的地。
前者就是宣告式編程,而後者就是命令式編程,雖然兩者的結果是一樣的,但是過程是全然不同的,當然也都各具有優缺點。
宣告式編程可以交由我們自己去決定我們認為最適合的方式,然後告訴電腦怎麼做來得我們想要的結果,但如果電腦已經知道一套很好的方式,我們何不節省時間與腦力,透過命令式編程直接告訴電腦我們要的結果,讓電腦來處理中間的過程呢?
這就是 React 的設計理念之一。
如果我們要偵測並且顯示一個按鈕的點擊次數,jQuery 的大致做法如下:
$("button").click(function() {
const number = Number($("#number").text());
$("p").text(number + 1);
})
而 React 的做法則是:
<button onClick={setNumber(prevNumber => prevNumber + 1)}</button>
<p>{number}<p>
我們可以看到使用 jQuery 的話我們必須明確的寫出如何更新畫面上的數字(命令式);若使用 React 我們只需要定義好資料和畫面的關係,如何更新畫面則交由 React 來處理(宣告式)。
在以上的例子中也許看不出來太大的差別,但當我們的畫面和操作邏輯越來越複雜,使用命令式編程出來的程式碼就會變得難以管理、擴充與維護,而使用宣告式編程則可以忽略操作邏輯的程式碼,只需專注於處理資料和畫面的關係。
React 並不是萬能的。
React 強大的地方在於 DOM 的管理與更新,但 DOM 之外的操作並不在 React 宣告式編程的掌握之中,例如發送 API 請求、資料訂閱、計時器、日誌紀錄等等我們稱之為會產生 side effect 的行為,因此 React 提供 useEffect 將這些行為延後,直到 virtual DOM 的變化更新到 real DOM 之後再一併處理。
React.useEffect(effect, dependencies);
例如:
fuction Timer() {
React.useEffect(() => {
const timer = setInterval(() => {
console.log('tick')
}, props.interval);
return () => {
clearInterval(timer);
}
}, [props.interval]);
return null;
}
如果 useEffect 的第二個參數 dependencies 傳入一個空 array,則只會執行一次 effect 函式:
React.useEffect(effect, []);
如果 useEffect 不傳入第二個參數 dependencies 則每次元件 rerender 都會執行 effect 函式:
React.useEffect(effect);
在 React 16.8 之前,React 開發者只能使用類別元件來處理 side effect,因為只有類別元件提供各種不同的生命週期函式,常用的有 componentDidMount、componentDidUpdate、componentWillUnmount 等等,因此在學習 useEffect 時大家習慣用類別元件的生命週期函式來和 useEffect 類比,但 useEffect 其實提供一種完全不同的開發的心智模式:
不然 React 提供 useComponentDidMount、useComponentDidUpdate、useComponentWillUnmount 這些 API 不就好了嗎?透過連結我們既有的知識的確可以幫助我們學習,但有可能使我們被既有的知識框架綁架,身處於一個技術快速發展的環境,值得我們再三思考,大家共勉之。
參考資料:
- Hooks API Reference – React - https://reactjs.org/docs/hooks-reference.html#useeffect
- 命令式编程(Imperative) vs声明式编程( Declarative) - 知乎 - https://zhuanlan.zhihu.com/p/34445114
- React Native教學 Part 3.5 - 概念分析:Declarative Programming - Carson's Tech Note - https://carsonwah.github.io/react-native-part3.5-declarative.html