在代碼中調用setState函數以後,React 會將傳入的參數對象與組件當前的狀態合併,而後觸發所謂的調和過程(Reconciliation)。
通過調和過程,React 會以相對高效的方式根據新的狀態構建 React 元素樹而且着手從新渲染整個UI界面。
在 React 獲得元素樹以後,React 會自動計算出新的樹與老樹的節點差別,而後根據差別對界面進行最小化重渲染。
在差別計算算法中,React 可以相對精確地知道哪些位置發生了改變以及應該如何改變,這就保證了按需更新,而不是所有從新渲染。react
簡單而言,React Element 是描述屏幕上所見內容的數據結構,是對於 UI 的對象表述。典型的 React Element 就是利用 JSX 構建的聲明式代碼片而後被轉化爲createElement的調用組合。而 React Component 則是能夠接收參數輸入而且返回某個 React Element 的函數或者類。更多介紹能夠參考React Elements vs React Components。算法
在組件須要包含內部狀態或者使用到生命週期函數的時候使用 Class Component ,不然使用函數式組件。瀏覽器
this.refs.textInputRefs 是 React 提供給咱們的安全訪問 DOM 元素或者某個組件實例的句柄。
咱們能夠爲元素添加ref屬性而後在回調函數中接受該元素在 DOM 樹中的句柄,該值會做爲回調函數的第一個參數返回:安全
class CustomForm extends Component { handleSubmit = () => { console.log("Input Value: ", this.input.value) } render () { return ( <form onSubmit={this.handleSubmit}> <input type='text' ref={(input) => this.input = input} /> <button type='submit'>Submit</button> </form> ) } }
上述代碼中的input域包含了一個ref屬性,該屬性聲明的回調函數會接收input對應的 DOM 元素,咱們將其綁定到this指針以便在其餘的類函數中使用。另外值得一提的是,refs 並非類組件的專屬,函數式組件一樣可以利用閉包暫存其值:數據結構
function CustomForm ({handleSubmit}) { let inputElement return ( <form onSubmit={() => handleSubmit(inputElement.value)}> <input type='text' ref={(input) => inputElement = input} /> <button type='submit'>Submit</button></form> ) }
Keys 是 React 用於追蹤哪些列表中元素被修改、被添加或者被移除的輔助標識。閉包
render () { return ( <ul>{this.state.todoItems.map(({task, uid}) => { return <li key={uid}>{task}</li> })}</ul> )}
在開發過程當中,咱們須要保證某個元素的 key 在其同級元素中具備惟一性。在 React Diff 算法中 React 會藉助元素的 Key 值來判斷該元素是新近建立的仍是被移動而來的元素,從而減小沒必要要的元素重渲染。此外,React 還須要藉助 Key 值來判斷元素與本地狀態的關聯關係,所以咱們毫不可忽視轉換函數中 Key 的重要性。框架
React 的核心組成之一就是可以維持內部狀態的自治組件,不過當咱們引入原生的HTML表單元素時(input,select,textarea 等),咱們是否應該將全部的數據託管到 React 組件中仍是將其仍然保留在 DOM 元素中呢?
這個問題的答案就是受控組件與非受控組件的定義分割。受控組件(Controlled Component)代指那些交由 React 控制而且全部的表單數據統一存放的組件。
譬以下面這段代碼中username變量值並無存放到DOM元素中,而是存放在組件狀態數據中。
任什麼時候候咱們須要改變username變量值時,咱們應當調用setState函數進行修改。classdom
ControlledForm extends Component { state = { username: '' } updateUsername = (e) => { this.setState({ username: e.target.value, }) } handleSubmit = () => { } render () { return ( <form onSubmit={this.handleSubmit}> <input type='text' value={this.state.username} onChange={this.updateUsername} /> <button type='submit'>Submit</button> </form> ) }}
而非受控組件(Uncontrolled Component)則是由DOM存放表單數據,並不是存放在 React 組件中。咱們可使用 refs 來操控DOM元素:函數
class UnControlledForm extends Component { handleSubmit = () => { console.log("Input Value: ", this.input.value) } render () { return ( <form onSubmit={this.handleSubmit}> <input type='text' ref={(input) => this.input = input} /> <button type='submit'>Submit</button> </form> ) }}
居然非受控組件看上去更好實現,咱們能夠直接從 DOM 中抓取數據,而不須要添加額外的代碼。不過實際開發中咱們並不提倡使用非受控組件,由於實際狀況下咱們須要更多的考慮表單驗證、選擇性的開啓或者關閉按鈕點擊、強制輸入格式等功能支持,而此時咱們將數據託管到 React 中有助於咱們更好地以聲明式的方式完成這些功能。引入 React 或者其餘 MVVM 框架最初的緣由就是爲了將咱們從繁重的直接操做 DOM 中解放出來。
React 下一代調和算法 Fiber 會經過開始或中止渲染的方式優化應用性能,其會影響到 componentWillMount 的觸發次數。對於 componentWillMount 這個生命週期函數的調用次數會變得不肯定,React 可能會屢次頻繁調用 componentWillMount。若是咱們將 AJAX 請求放到 componentWillMount 函數中,那麼顯而易見其會被觸發屢次,天然也就不是好的選擇。性能
咱們應當將AJAX 請求放到 componentDidMount 函數中執行,
主要緣由有下:
若是咱們將 AJAX 請求放置在生命週期的其餘函數中,咱們並不能保證請求僅在組件掛載完畢後纔會要求響應。若是咱們的數據請求在組件掛載以前就完成,而且調用了setState函數將數據添加到組件狀態中,對於未掛載的組件則會報錯。而在 componentDidMount 函數中進行 AJAX 請求則能有效避免這個問題。
shouldComponentUpdate 容許咱們手動地判斷是否要進行組件更新,根據組件的應用場景設置函數的合理返回值可以幫咱們避免沒必要要的更新。
一般狀況下咱們會使用 Webpack 的 DefinePlugin 方法來將 NODE_ENV 變量值設置爲 production。編譯版本中 React 會忽略 propType 驗證以及其餘的告警信息,同時還會下降代碼庫的大小,React 使用了 Uglify 插件來移除生產環境下沒必要要的註釋等信息。
爲了解決跨瀏覽器兼容性問題,React 會將瀏覽器原生事件(Browser Native Event)封裝爲合成事件(SyntheticEvent)傳入設置的事件處理器中。這裏的合成事件提供了與原生事件相同的接口,不過它們屏蔽了底層瀏覽器的細節差別,保證了行爲的一致性。另外有意思的是,React 並無直接將事件附着到子元素上,而是以單一事件監聽器的方式將全部的事件發送到頂層進行處理。這樣 React 在更新 DOM 的時候就不須要考慮如何去處理附着在 DOM 上的事件監聽器,最終達到優化性能的目的。
createElement 函數是 JSX 編譯以後使用的建立 React Element 的函數,而 cloneElement 則是用於複製某個元素並傳入新的 Props。
是個函數,該函數會在setState函數調用完成而且組件開始重渲染的時候被調用,咱們能夠用該函數來監聽渲染是否完成:
this.setState( { username: 'tylermcginnis33' }, () => console.log('setState has finished and the component has re-rendered.') )
下述代碼有錯嗎?
this.setState((prevState, props) => { return { streak: prevState.streak + props.count } })
這段代碼沒啥問題,不過只是不太經常使用罷了
props是一個父組件傳遞給子組件的數據流,能夠一直的被傳遞到子孫組件中。然而 state表明的是子組件自身的內部狀態。從語義上講,改變組件的狀態,可能會致使dom結構的改變或者從新渲染。而props是父組件傳遞的參數,因此能夠被用於初始化渲染和改變組件自身的狀態,雖然大多數時候組件的狀態是又外部事件觸發改變的。咱們須要知道的是,不管是state改變,仍是父組件傳遞的 props改變,render方法均可能會被執行。