React Javascript 庫入門
已發表: 2022-02-16如果您在 WordPress 世界中度過任何時間,您可能會遇到 Zac Gordon。 Zac 是一位熱情而迷人的老師,專注於 WordPress 中的 Javascript。 他從 Matt Mullenweg 那裡借用了“Learn Javascript Deeply”這句話,並把它變成了他的個人口號。
在過去的幾年裡,Zac 製作了視頻課程、在線會議、現場演講和播客,專注於教您如何在 WordPress 中使用 Javascript。
我很高興地說我們正在與 Zac 合作寫一本書,“React Explained”。 React 是 WordPress 團隊為新的 Gutenberg 編輯器選擇的庫。 他們並不孤單——Drupal 和 Magento 都選擇了 React。
Zac 在 Twitter 上的 @zgordon 上實時發布他的寫作進度。 您還可以在 OSTraining 播客上聽到 Zac 談論 React。
在這本書的摘錄中,Zac 為您提供了 React 和一些關鍵概念的高級概述。
什麼是反應?
開箱即用,React 是一個用於構建用戶界面的庫。
儘管 React 是一個 JavaScript 庫,但 React 構建的接口是不可知的。
存在幾個 React 配套庫以使您構建的界面在瀏覽器、服務器、本機應用程序甚至 360 和 VR 環境中工作。 在本書中,我們專注於使用 ReactDOM,該庫管理將我們使用 React 構建的接口添加到客戶端網站和應用程序。 ReactDomServer、ReactNative 和 React360 也是您可能想要探索以在其他環境中使用 React 接口的庫。
除了為構建接口提供幫助函數外,React 的架構還允許您處理與接口的交互,無論這涉及事件處理、api 調用、狀態管理、接口更新還是更複雜的交互。
React 沒有提供像一些 JavaScript 框架那麼多的輔助函數。 這在很大程度上是我們將 React 稱為庫而不是框架的原因。 在使用 React 時,你仍然需要編寫大量的原生 JavaScript。
React 組件架構解釋
組件是一段獨立的、可重用的代碼(通過函數或類創建)。
React 使用組件架構來構建用戶界面和組織代碼。 一個簡單的 React 應用程序的主文件可能看起來像這樣。
// 導入 React 和其他組件 從“反應”導入反應; 從'react-dom'導入{渲染}; 從'./Header'導入標題; 從'./MainContent'導入MainContent; 從'./Footer'導入頁腳; 函數應用程序(){ 返回 ( <div className="app"> <標題/> <主要內容 /> <頁腳/> </div> ); } ReactDOM.render( <App />, document.getElementById("root"));
我們可以在這裡看到一些正在使用的組件。 <Header />、<MainContent /> 和 <Footer /> 都是組件。 App() 函數也是一個組件,我們可以在此示例的最後一行看到如何使用 ReactDOM 庫和 ReactDOM.render() 方法來管理將我們構建的 UI 添加到網頁中。
如果我們深入了解 <Header />、<MainContent /> 和 <Footer /> 組件,我們可能會看到更多組件的使用以及看起來像 HTML 標記的內容。
從“反應”導入反應; 從“../Ad”導入廣告; 從“../assets/logo.svg”導入徽標; 導出默認函數 Header() { 返回 ( <header className="app-header"> <廣告 /> <img src={logo} className="app-logo" alt="logo" /> <h1 className="app-title">網站名稱</h1> </標題> ); }
在上面的這個 <Header /> 組件中,我們可以看到我們正在引入另一個名為 <Ad /> 的組件。 大多數 React 應用程序包含多層組件嵌套,就像我們在 <App />、<Header /> 和 <Ad /> 中看到的那樣。
我們還在 React 代碼中看到了 HTML 元素的使用。 這要歸功於一個名為 JSX 的庫,它允許您直接在 JavaScript 中編寫“HTML 標記”。 由於我們使用 React 創建用戶界面,並且 Web 上的用戶界面涉及 HTML 標記,因此我們會在 UI 組件中看到類似 HTML 的元素。 我們將在本書中深入探討 JSX。
如果我們查看使用 React 360(React 的 VR 庫)構建的簡單 React 應用程序的一些代碼,我們調用的實際組件會有所不同,但組件架構仍然存在。
從“反應”導入反應; 進口 { 文本, 看法, 虛擬按鈕, } 來自'react-360'; 類幻燈片擴展 React.Component { // 為簡潔起見刪除代碼 返回 ( <查看樣式={styles.wrapper}> <查看樣式={styles.controls}> <VrButton onClick={this.prevPhoto}> <Text>{'上一個'}</Text> </VrButton> <VrButton onClick={this.nextPhoto}> <Text>{'下一個'}</Text> </VrButton> <查看> <Text style={styles.title}>{current.title}</Text> </查看> </查看> ); }
上面的代碼創建了幾層 360 度視圖,並覆蓋了一些按鈕和文本。 雖然實際的代碼可能沒有完全的意義,但應該清楚的是我們有幾個嵌套的組件代表視圖、按鈕和文本。
這是一個很好的例子,因為你可以通過傳遞不同的參數或 React 所謂的 props 來了解相同的組件是如何以不同的方式重用的。 了解數據如何通過 React 組件對於了解使用 React 構建的典型組件架構非常重要。
React 數據流解釋
React 遵循在組件層次結構中的最高點獲取和設置數據的約定,以便數據以單向方向向下通過應用程序。讓我們看一下這個例子,想像一下我們需要的一些數據類型對於各種組件。
函數應用程序(){ 返回( <React.Fragment> <標題/> <內容/> <側邊欄 /> <頁腳/> </React.Fragment> ); }
<Header /> 和 <Footer /> 可能需要類似站點名稱的名稱。 特定頁面的主要內容需要傳遞給 <Content />。 一些額外的小部件數據可能需要轉到 <Sidebar />。
函數應用程序(){ 常量 siteTitle = getSiteTitle(); 常量小部件 = getWidgets(); 常量 mainContent = getPageContent(); 返回( <React.Fragment> <標題站點標題={站點標題} /> <內容 mainContent={mainContent} /> <Sidebar widgets={widgets} /> <頁腳站點標題={站點標題} /> </React.Fragment> ); }
這種組成屬性名稱並為其分配值的約定是我們將數據傳遞到組件的方式。

現在 <Header /> 和 <Footer /> 可以訪問 siteTitle,<Content /> 可以訪問 mainContent,<Sidebar /> 可以訪問它需要的小部件。
一個重要的注意事項是,這種將數據傳遞到組件的模式只傳遞了一層數據。 <Header /> 內的組件不會自動訪問 siteTitle。
功能標題(道具){ 返回( <標題> <p>我們可以在這裡看到 {props.siteTitle}。</p> <PageHeader siteTitle={props.siteTitle} /> <PageSubHeader /> </標題> ); }
您可以在此處看到,在 <Header /> 內部,我們可以調用 props.siteTitle 並可以訪問我們傳遞給它的值。 但是,如果我們想在 <PageHeader /> 組件中訪問 siteTitle,我們也必須手動向下傳遞該信息。
當一個組件接收一個值作為 props 時,它不應該修改它。 道具應該作為不可變數據通過組件樹。 這可以確保任何引用 prop 的組件都引用與其子組件的父級相同的值。
prop 的值只能在最初設置 prop 值並開始通過組件樹向下傳遞的組件中更改。 在我們上面的示例代碼中,<App /> 組件可以更改 siteTitle 的值,但 <Header /> 或 <PageHeader /> 組件不應該。
要了解 React 應用程序中動態數據如何更新的流程,需要討論狀態以及如何將事件處理程序作為 props 傳遞。
React 組件狀態解釋
正如我們所了解的,數據通過組件作為道具不變地向下流動。 數據設置在樹中的最高組件,所有子組件都需要作為道具傳遞信息。
在某些情況下,此數據只接收一次,無需更改。 在許多情況下,儘管數據必須保持動態,並且能夠在任何給定時間更新,並且該更新反映在所有子組件中。
為了跟踪 React 中變化的數據,我們有一個 React 狀態對象和一組幫助函數來更新狀態值。
這是一個會自我更新的計數器的示例。 計數器的值是該組件中的動態值,因此可以很好地說明何時依賴狀態。 請注意,要使組件具有狀態,我們必須使用 JavaScript 類而不是函數。
類計數器擴展組件{ 狀態= { 計數器:0 }; 處理計數 = () => { 這個.setState({ 計數器:this.state.counter + 1 }); }; 使成為() { 返回 ( <div> <h1>{this.state.counter}</h1> <button onClick={this.handleCount}>計數!!</button> </div> ); } }
現在需要注意的是,此狀態僅限於此組件。 計數器中的狀態值對子組件或父組件不可用。
因此,在一個更複雜的示例中,如下所示,我們必須將 counter down 的值作為道具傳遞給子元素。
類計數器擴展組件{ 狀態= { 計數:0 }; 處理計數 = () => { 這個.setState({ 計數:this.state.count + 1 }); }; 使成為() { 返回 ( <div> <PageHeader count={this.state.count} /> <button onClick={this.handleCount}>計數!!</button> </div> ); } }
每次我們更新 <Counter /> 組件中的狀態時,<PageHeader /> 計數屬性都會更新
功能頁眉(道具){ 返回 <h1>{props.count}</h1>; }
這種方法的好處是,無論何時更新狀態,都會自動將新值傳遞給任何子組件,並將 prop 的值設置為 state。
這使我們能夠為動態數據提供單點真實性。 事實的來源是狀態中的值,由單個組件管理。 子組件中此值的所有實例都是作為 props 接收的不可變值,不應在此組件之外更改。
在層次結構中出現在該組件上方的組件將無法訪問此數據,因為它僅通過道具向下傳遞。 我們再次看到為什麼我們嘗試從層次結構中更高的組件設置和管理狀態,以便數據可供所有需要它的人使用。
還有一些其他的架構模式,比如高階組件和上下文 API,它們可以避免通過你的應用程序手動傳遞大量的 props。 稍後我們將更深入地探討這些。 現在,我們要確保在我們開始走捷徑之前,我們了解事物通常如何運作的高級概述。
在 React 中更新組件狀態
現在,當我們想要觸發從子組件更新狀態時會發生什麼?
例如,想像一下,在上面的示例中,我們希望在我們的主 <Counter /> 組件中擁有一個 <Button /> 組件而不是硬編碼按鈕? 這實際上在復雜的應用程序中很常見。
在 React 世界中,解決此問題的方法是傳遞事件處理函數,該函數使用 setState down 作為 prop 來更新狀態。 然後可以從任何子組件調用它,但該操作將發生在設置狀態的原始組件中,並且也具有更新它的能力。 存在其他模式,但這種方法是最基本的。
如果您不熟悉將函數作為參數傳遞,那麼它是完全有效的 vanilla JavaScript。
一旦狀態更新,它將通過 props 向下傳遞到組件層次結構。
這是一個看起來像的例子。
類計數器擴展組件{ 狀態= { 計數:0 }; 處理計數 = () => { 這個.setState({ 計數:this.state.count + 1 }); }; 使成為() { 返回 ( <div> <PageHeader count={this.state.count} /> <Button handleCount={this.handleCount} /> </div> ); } } 功能頁眉(道具){ 返回( <h1>{props.count}</h1> ); } 功能按鈕(道具){ 返回( <button onClick={props.handleCount}>計數!!</button> ); }
在這裡,我們可以看到一個 React 如何處理數據流的簡單示例。 數據只有一個事實。 這存在於狀態集中並從單個組件更新。 數據通過 props 以一種方式向下流過嵌套的組件樹。
如果需要從最初設置的組件以外的組件更新狀態,則可以將事件處理程序作為道具傳遞給必要的子組件。 這使數據保持不變並以一種方式流動,因為即使子組件觸發更改,該更改也會發生在原始組件的更高位置。
當我們將 prop 的值分配給 state 中的某物時,如下所示,每當 state 發生變化時,該 prop 的值都會自動更新。
<PageHeader 計數器={this.state.count} />
引用該道具值的任何其他子組件也將自動接收更新。 這就是 React 中數據流的美妙之處。
這可能需要一點時間來適應,具體取決於您過去使用 JavaScript 處理此類問題的方式。 然而,這一切都應該成為我們能夠深入解釋 React 的一個很好的起點。