學習 React.js 需要了解的一些概念
?大家好,我是前端西瓜哥。
React.js 是被廣泛使用的用于構建用戶界面的 JS 庫。下面給大家介紹一下學習 React 需要了解的一些概念。
聲明式
在 React 這類框架流行之前,我們更新 UI,都是命令式的:我們需要手動指定元素,然后命令它改變樣式。
// 純 JS 寫法
document.querySelector('#content') = '前端西瓜哥';
// JQuery 寫法
$('#content').text('content');
這種寫法其實是相當繁瑣的。你可能需要給元素加上 id,加上 class 作以區分,可能還需通過查找當前元素的父元素來界定區域,然后手動作添加子元素、進行修改樣式、移除等操作。
所有的事情,都要自己一個個去操作,事無巨細,容易寫錯。
React 和 Vue 這類框架的出現,讓實際項目開發中命令式的寫法成為了歷史(只是偶爾還是會用到一點命令式寫法)。
React 的編碼是 聲明式 的,你只需要維護好狀態,然后在必要的時候通知 React,React 會自動幫你將 UI 渲染好。
class Compoent extends React.Component {
state = { content: '前端西瓜哥' };
updateContent = () => {
this.setState({ content: 'fe_watermelon' });
};
render() {
return (
<div>
<div>{this.state.content}</div>
<button onClick={() => this.updateContent()}>更新 content</button>
</div>
);
}
}
// 渲染為
// <div>前端西瓜哥</div>
React 中用 state 對象來保存可能會發生變化的狀態,然后在 HTML 中用 {變量} 的方式嵌入,并通過 setState() 方法來更新狀態,并重新渲染 UI。
UI = f(data)
數據映射到 UI 的操作過程,全部交給 React 做了,再也不用擔心自己手寫的 DOM 更新寫錯了。你要做的只是更新狀態,以及設置好狀態在 HTML 中渲染的地方。
這種修改好狀態,然后調用方法更新 UI 的做法,其實挺像做小游戲的。比如我們要做一個俄羅斯方塊,當發生動作時,我們要更新好每個像素的位置(更新數據),然后調用自己實現的 render 方法,先清空畫布,然后一個個繪制出來(映射 UI)。
組件化
組件化是什么?其實就是將模板、樣式、腳本組合起來,成為一個組件。我們編寫好一個個小的組件,然后將組件組合起來,就組成了我們的 UI 界面。
要想構建復雜的應用,合適的抽象是很重要的。對于 UI 來說,一種比較正確的思路,是將 UI 的分割成各個部分,我們只需要專注于一個職責專一的組件上,完成它后,再和其他的組件聯合在一起,一點點構建出復雜的應用。
比如一個待辦功能,我們可以抽象成下面這個樣子。
<TodoContainer>
<TodoInput />
<TodoList />
</TodoContainer>
虛擬 DOM
為了高效地更新 DOM,React 的底層使用了虛擬 DOM 來表示真實的 DOM 結構。
沒有使用真實 DOM,是因為真實 DOM 對象比較復雜,有非常多的屬性,比較占內存,所以抽象了一層 虛擬 DOM,此外還能附帶上組件節點。
當狀態更新時,會對比新舊虛擬 DOM 樹得到補丁,通過打補丁的方式去更新真實 DOM 樹。
React 中新舊 DOM 對比算法做了優化,要比普通的樹比較算法要高效,這是 React 能被運用到實際生產環境的一個重要原因。
跨平臺
得益于 React 中虛擬 DOM 的實現,React 支持通過 React Native 編譯為其他平臺語言,來構建移動原生應用,比如 Andorid 或 iOS 原生應用。
虛擬 DOM 其實是真正 DOM 的一層抽象,這個抽象和平臺無關,因此我們可以根據這層抽象去做跨平臺的實現,讓一套代碼得以運行在不同平臺。
但虛擬 DOM 并不能涵蓋不同平臺一些特有的 API,所以你其實還是要懂一些原生 APP 的知識的,對一些情況做特殊處理。
但至少,React 提供了一種跨平臺的方案。
JSX
React 首先是一個 JS 庫,它的語法不能跳脫 JS 的語法。在 JS 環境中,React 通過 React.crreatElement 來描述 DOM。
創建一個內容為 this.state.content 的 div 元素,我們需要這樣寫。
const el = React.createElement('div', {}, this.state.content);
第一個是 HTML 元素名或組件名,第二個是屬性,第三個是子元素或子組件。
只是描述的一個 DOM 元素還算簡單,但我們的頁面是由復雜的 DOM 元素組織而成的,如果用上面這種寫法,代碼容易出錯,也不方便進行維護。
于是 React 推出了 JSX,全稱為 JavaScript Syntax Extension,即 JS 語法的擴展增強。通過 JSX,我們就可以實現 “在 JS 中寫 HTML”。
const el = <div>{this.state.content}</div>;
但 JSX 還是不能被瀏覽器識別,需要編譯為 JS。編譯后,里面的這種 <div></div> 就會轉換為使用了 React.createElement('div') 的代碼。
單向數據流
React 要求數據從父組件通過 props 流向子組件,這樣就能更好地定位組件中的某個數據的來源。
當然我們還是可以通過額外傳遞一個可以修改父組件狀態方法給子組件,通過它去更新傳給子組件的數據。
這樣就能實現雙向的數據流,但它依舊是顯式的,仍然有助于理解程序的運轉流程。
React Hooks
React 支持通過類或函數的方式編寫組件,分別稱為 類組件 和 函數組件。
類組件可以創建對象,所以自身可以維護狀態是理所當然的事情。
一般來說,函數組件是不支持狀態的,因為它是一個函數,只會接收外部傳入的數據,然后渲染,內部沒辦法保持狀態,因為它不是對象,只是一個用完就結束的函數。
函數組件不能使用內部狀態的這種情況,在 React 推出了 React Hooks 之后解決了。
const Compoent = () => {
const [content, setContent] = useState('前端西瓜哥');
return (
<div>
<div>{content}</div>
<button onClick={() => setContent('fe_watermelon')}>更新</button>
</div>
);
};
我們在函數組件內使用 useState() 就可以創建一個內部狀態,且可以通過 setXxx() 進行更新。
我第一次看到 React Hooks,就覺得這簡直就是魔法,驚為天人。
底層其實是用一個額外的有序列表保存好了每個狀態,和函數組件進行了綁定。為了做到這點,React 要求 Hooks 必須在每次執行時,保證順序相同。
React Hooks 的一個優點是,將邏輯的最小單元從組件,縮小為更細粒度的 hooks 的組合。這讓我們編寫組件更加靈活。