大約半個月前,我一直在思考一個問題,Angular、React 和 Vue,究竟該學什么?
聽取了幾位前輩的意見,也綜合考慮了各方面的原因,最終選擇了 React,希望我“沒有選錯”。
十天的時間,把 React 的快速入門文檔給過了一遍,整理了一些筆記,現在記錄如下。
JSX 簡介
可以在 JSX 中嵌入 JavaScript 表達式,並用花括號包裹。
使用括號包裹 JSX 表達式,並將其拆分為多行以提高可讀性。也可以避免自動插入分號。
由於 JSX 是在 JavaScript 中使用的,React DOM 的屬性使用 camelCase 命名。
JSX 是安全的,可以防止注入攻擊。
渲染元素
元素是元素,組件是組件。
React 元素是只讀的,一旦創建,就不能改變它的子元素和屬性。
就目前來說,更新 UI 的唯一方法是創建一個新的元素,並傳遞給 ReactDOM.render()
。
在實踐中,大多數應用程序只調用一次 ReactDOM.render()
。
當調用 ReactDOM.render()
時,只有發生改變的節點才會被 React DOM 更新。
組件和屬性
從概念上講,組件就像 JavaScript 函數,它們接收輸入,並返回 React 元素。
可以使用 ECMAScript 6 的類來定義組件,類有一些額外的功能。
組件的名稱總是以大寫字母開始。
組件中可以使用組件。
如果要將 React 集成到現有應用程序中去,可以優先編寫小的組件,自下而上。
組件越小越好。
一個好的經驗法則:如果 UI 被多次使用,或者 UI 本身足夠復雜,那么就可以將它做成組件。
組件的屬性是只讀的。
所有的 React 組件必須像純函數那樣使用它們的屬性。
狀態和生命周期
狀態類似於屬性,但它是私有的,完全由組件控制。
componentDidMount()
在組件呈現到 DOM 之后運行。
狀態有特殊的意義,如果需要存儲不影響視覺輸出的內容,並不在 render()
中使用,則可以手動向類中添加其它字段。
不要直接修改狀態,而是通過調用 this.setState()
來修改狀態。
React 可以將多個 this.setState()
調用批處理為一個 this.setState()
以實現性能上的提升。
更新狀態是異步的,不能依賴上一個狀態值來計算下一個狀態值。
要解決它,應當使用函數而不是對象。該函數將接收先前的狀態做為第一個參數,並將屬性做為第二個參數。
當調用 this.setState()
時,React 會將對象合並到當前狀態。
父組件和子組件都不知道某個組件是有狀態還是無狀態的,並且不應該關心它是否被定義為函數或類。
組件可以選擇將狀態做為屬性傳遞給子組件。
組件以及它的數據只能影響子組件,這通常被稱為自上而下或單向數據流。
處理事件
DOM 事件使用全小寫命名,而 React 事件使用 camelCase 命名。
使用 JSX 傳遞一個函數做為事件處理程序。
不能返回 false 來阻止 React 中的默認行為。必須顯式調用 event.preventDefault()
。
當使用 ECMAScript 6 的類定義組件時,常見的做法是將事件處理程序做為類上的方法。
如果在 ECMAScript 6 的類中使用事件,必須手動在構造函數中綁定。
或者在回調中使用箭頭函數,但是每次呈現時都會創建不同的回調。大多數情況下這么做是可以的,但是在底層組件中,可能會執行額外的渲染,一般建議在構造函數中綁定,以避免這種性能問題。
條件呈現
如果條件過於復雜,可能是提取組件的好時機。
列表和鍵
應給數組中的元素賦予鍵,以給元素一個唯一的身份。
如果數組中的元素是組件,應該將鍵保存在組件上,而不是組件中的元素上。
一個好的經驗法則是,map()
中的元素需要鍵。
鍵被 React 使用,不會傳遞給組件,如果要使用,則使用不同的名稱,做為屬性顯式傳遞。
如果嵌套太深,可能是提取組件的好時機。
表單
值不會隨用戶的輸入而改變,因為組件已聲明值,且始終是原來的值。
若要響應用戶輸入的值,則使用 onChange
事件保存用戶輸入的值。
要初始化具有非空值的不受控制的組件,可以使用 defaultValue/defaultChecked
屬性。
對於 <input>
和 <textarea>
應該使用 onChange
而不是 oninput
。
在 React 中,要使用受控制的表單組件。
如果在 <textarea>
中使用文本節點插入值,那么它的行為將類似於 defaultValue
。
狀態提升
對於在 React 應用程序中發生變化的任何數據,應該有一個單一的“真實來源”。通常,首先將狀態添加到需要渲染的組件。然后,如果其他組件也需要它,可以將其提升到最接近的共同祖先。而不是嘗試在不同組件之間同步狀態,應該依賴於自上而下的數據流,或者說是單向數據流。
如果一些變量可以從屬性或狀態派生,它可能不應該設置為狀態。
組合與繼承
建議使用組合而不是繼承來重用組件之間的代碼。
組件可以接收任意屬性,包括原始值、React 元素以及函數。
如果要在組件之間重用非 UI 的功能,建議將其提取到單獨的 JavaScript 模塊中。
在 React 中思考
使用 React 構建界面的思考過程:
- 打破 UI 進入組件層次結構。
- 在 React 中構建靜態版本。
- 確定最少但完整的狀態。
- 確定狀態應該儲存在哪個組件。
- 添加反向數據流。
單一職責原則:一個組件應該只做一件事。
要知道它是不是狀態,只需要問三個問題:
- 數據是從父級過來的嗎?如果是,它可能不是狀態。
- 數據是否隨時間保持不變?如果是,它可能不是狀態。
- 可以根據組件的屬性或狀態來計算它嗎?如果是,它可能不是狀態。
數據不是從父級過來的,會隨時間變化,並不可以被計算出來,那么它就是狀態。
對於應用程序中的每個狀態:
- 確定使用該狀態的每個組件。
- 查找最接近的共同祖先。
- 最接近的共同祖先應該擁有該狀態。