核心要點
setState()
方法、Context API 和最近引入的 Hooks。 在學習 React Native 的過程中,狀態管理是最難掌握的概念之一,因為有很多方法可以實現它。 npm 註冊表上有無數的狀態管理庫——例如 Redux——並且有無數基於其他狀態管理庫構建的庫來簡化原始庫本身——例如 Redux Easy。每週都會在 React 中引入一個新的狀態管理庫,但是自從引入 React 以來,維護應用程序狀態的基本概念保持不變。
在 React Native 中設置狀態最常見的方法是使用 React 的 setState()
方法。我們還可以使用 Context API 來避免 props 鑽取,並在不將其傳遞給樹中各個子組件的情況下向下傳遞多層狀態。
最近,Hooks 在 React v16.8.0 中出現,這是一種簡化在 React 中使用狀態的新模式。 React Native 在 v0.59 中獲得了它。
在本教程中,我們將學習狀態的實際含義,以及 setState()
方法、Context API 和 React Hooks。這是在 React Native 中設置狀態的基礎。所有庫都是基於上述基本概念構建的。因此,一旦您了解了這些概念,理解庫或創建自己的狀態管理庫就會很容易。
想從頭開始學習 React Native 嗎?本文摘自我們的高級庫。立即加入 SitePoint Premium,獲取涵蓋基礎知識、項目、技巧和工具等的完整 React Native 圖書集,每月只需 9 美元。
什麼是狀態?
任何隨時間變化的事物都被稱為狀態。如果我們有一個計數器應用程序,則狀態就是計數器本身。如果我們有一個待辦事項應用程序,則待辦事項列表會隨時間變化,因此此列表將是狀態。即使是輸入元素在某種意義上也是一個狀態,因為它隨著用戶在其中鍵入而隨時間變化。
setState 簡介
既然我們知道什麼是狀態,讓我們了解 React 如何存儲它。
考慮一個簡單的計數器應用程序:
import React from 'react'; import { Text, Button } from 'react-native'; class Counter extends React.Component { state = { counter: 0, }; render() { const { counter } = this.state; return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => this.setState({ counter: counter + 1 })} /> <Button title="Decrement" onPress={() => this.setState({ counter: counter - 1 })} /> </> ); } }
在這個應用程序中,我們將狀態存儲在構造函數中的一個對象內,並將其分配給 this.state
。
請記住,狀態只能是一個對象。您不能直接存儲數字。這就是為什麼我們在對象內創建了一個 counter
變量。
在 render
方法中,我們從 this.state
中解構 counter
屬性並在 <h1>
內呈現它。請注意,目前它只會顯示靜態值 (0)。
您也可以按如下方式在構造函數之外編寫狀態:
import React from 'react'; import { Text, Button } from 'react-native'; class Counter extends React.Component { state = { counter: 0 }; render() { const { counter } = this.state; return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => this.setState({ counter: counter + 1 })} /> <Button title="Decrement" onPress={() => this.setState({ counter: counter - 1 })} /> </> ); } }
現在假設我們希望“ ”和“-”按鈕能夠工作。我們必須在它們各自的 onPress
處理程序內編寫一些代碼:
import React from 'react'; import { Text, Button } from 'react-native'; class Counter extends React.Component { state = { counter: 0 }; render() { const { counter } = this.state; return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => this.setState(prevState => ({ counter: prevState.counter + 1 }))} /> <Button title="Decrement" onPress={() => this.setState(prevState => ({ counter: prevState.counter - 1 }))} /> </> ); } }
現在,當我們點擊“ ”和“-”按鈕時,React 會重新渲染組件。這是因為使用了 setState()
方法。
setState()
方法會重新渲染已更改的樹的一部分。在這種情況下,它會重新渲染 <h1>
。
因此,如果我們點擊“ ”,它會將計數器增加 1。如果我們點擊“-”,它會將計數器減少 1。
請記住,您不能通過更改 this.state
來直接更改狀態;執行 this.state = counter 1
將不起作用。
此外,狀態更改是異步操作,這意味著如果您在調用 this.setState
後立即讀取 this.state
,它將不會反映最新的更改。
在這裡,我們使用“函數作為回調”語法來使用 setState()
,如下所示:
import React from 'react'; import { Text, Button } from 'react-native'; class Counter extends React.Component { state = { counter: 0 }; render() { const { counter } = this.state; return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => this.setState(prevState => ({ counter: prevState.counter + 1 }))} /> <Button title="Decrement" onPress={() => this.setState(prevState => ({ counter: prevState.counter - 1 }))} /> </> ); } }
“函數作為回調”語法提供最新的狀態——在這種情況下為 prevState
——作為 setState()
方法的參數。
通過這種方式,我們可以獲得對狀態的最新更改。
什麼是 Hooks?
Hooks 是 React v16.8 的新增功能。早些時候,您只能通過創建類組件來使用狀態。您不能在函數組件本身中使用狀態。
隨著 Hooks 的添加,您可以在函數組件本身中使用狀態。
讓我們將上面的 Counter
類組件轉換為 Counter
函數組件並使用 React Hooks:
import React from 'react'; import { Text, Button } from 'react-native'; const Counter = () => { const [counter, setCounter] = React.useState(0); return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => setCounter(counter + 1)} /> <Button title="Decrement" onPress={() => setCounter(counter - 1)} /> </> ); };
請注意,我們將類組件的代碼行數從 18 行減少到僅 12 行。此外,代碼也更容易閱讀。
讓我們回顧一下上面的代碼。首先,我們使用 React 的內置 useState
方法。 useState
可以是任何類型——例如數字、字符串、數組、布爾值、對像或任何類型的數據——與 setState()
不同,setState()
只能有一個對象。
在我們的計數器示例中,它接受一個數字並返回一個包含兩個值的數組。
數組中的第一個值是當前狀態值。因此,counter
當前為 0。
數組中的第二個值是可以讓您更新狀態值的函數。
在我們的 onPress
中,我們可以直接使用 setCounter
更新 counter
。
因此,我們的增量函數變為 setCounter(counter 1)
,我們的減量函數變為 setCounter(counter - 1)
。
React 有許多內置的Hooks,例如useState
、useEffect
、useContext
、useReducer
、useCallback
、useMemo
、useRef
、useImperativeHandle
、useLayoutEffect
和useDebugValue
——您可以在React Hooks 文檔中找到更多信息。
此外,我們還可以構建自己的自定義 Hooks。
構建或使用 Hooks 時,需要遵循兩條規則:
useState
和 useEffect
調用之間正確保留 Hooks 狀態的原因。 通過遵循此規則,您可以確保組件中的所有有狀態邏輯都從其源代碼中清晰可見。
Hooks 非常容易理解,並且在向函數組件添加狀態時很有用。
Context API
Context 提供了一種在組件樹中傳遞數據的方法,無需在每一層手動傳遞 props。
在典型的 React Native 應用程序中,數據通過 props 自上而下傳遞。如果 React 應用程序中有多個組件級別,並且組件樹中的最後一個子組件想要從最頂層的父組件檢索數據,那麼您必須單獨向下傳遞 props。
考慮下面的示例。我們想將 theme
的值從 App
組件傳遞到 Pic
組件。通常,如果不使用 Context,我們將通過每個中間級別傳遞它,如下所示:
import React from 'react'; import { Text, Button } from 'react-native'; class Counter extends React.Component { state = { counter: 0, }; render() { const { counter } = this.state; return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => this.setState({ counter: counter + 1 })} /> <Button title="Decrement" onPress={() => this.setState({ counter: counter - 1 })} /> </> ); } }
theme
的值從 App -> Home -> Profile -> Pic 傳遞。上述問題被稱為 props 鑽取。
這是一個簡單的示例,但考慮一個實際的應用程序,其中有數十個不同的級別。
僅僅為了在最後一個子組件中使用它而通過每個子組件傳遞數據變得很困難。因此,我們有 Context。
Context 允許我們直接從 App -> Pic 傳遞數據。
以下是如何使用 Context API 進行操作:
import React from 'react'; import { Text, Button } from 'react-native'; class Counter extends React.Component { state = { counter: 0, }; render() { const { counter } = this.state; return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => this.setState({ counter: counter + 1 })} /> <Button title="Decrement" onPress={() => this.setState({ counter: counter - 1 })} /> </> ); } }
首先,我們使用 React.createContext
API 創建 ThemeContext
。我們將 light
設置為默認值。
然後,我們在提供 theme
作為 prop 的情況下,使用 ThemeContext.Provider
包裝 App
組件的根元素。
最後,我們使用 ThemeContext.Consumer
作為渲染 prop 來獲取 theme
值為 dark
。
渲染 prop 模式很好,但是如果我們有多個上下文,則可能會導致回調地獄。為了避免回調地獄,我們可以使用 Hooks 而不是 ThemeContext.Consumer
。
我們唯一需要更改的是 Profile
組件的實現細節:
import React from 'react'; import { Text, Button } from 'react-native'; class Counter extends React.Component { state = { counter: 0 }; render() { const { counter } = this.state; return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => this.setState({ counter: counter + 1 })} /> <Button title="Decrement" onPress={() => this.setState({ counter: counter - 1 })} /> </> ); } }
通過這種方式,我們不必擔心回調地獄。
跨組件共享狀態
到目前為止,我們只在組件本身中管理狀態。現在我們將了解如何在組件之間管理狀態。
假設我們正在創建如下所示的簡單待辦事項列表應用程序:
import React from 'react'; import { Text, Button } from 'react-native'; class Counter extends React.Component { state = { counter: 0 }; render() { const { counter } = this.state; return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => this.setState(prevState => ({ counter: prevState.counter + 1 }))} /> <Button title="Decrement" onPress={() => this.setState(prevState => ({ counter: prevState.counter - 1 }))} /> </> ); } }
現在,如果我們想從 AddTodo
組件添加一個待辦事項,它將如何在 TodoList
組件的 todos
prop 中顯示?答案是“提升狀態”。
如果兩個兄弟組件想要共享狀態,則必須將狀態提升到父組件。完整的示例應如下所示:
import React from 'react'; import { Text, Button } from 'react-native'; class Counter extends React.Component { state = { counter: 0 }; render() { const { counter } = this.state; return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => this.setState(prevState => ({ counter: prevState.counter + 1 }))} /> <Button title="Decrement" onPress={() => this.setState(prevState => ({ counter: prevState.counter - 1 }))} /> </> ); } }
在這裡,我們將狀態保存在 App
組件中。我們使用 React Hook useState
將 todos
存儲為空數組。
然後,我們將 addTodo
方法傳遞給 AddTodo
組件,並將 todos
數組傳遞給 TodoList
組件。
AddTodo
組件將 addTodo
方法作為 prop 接收。按下按鈕後應調用此方法。
我們還有一個 TextInput
元素,它也使用 React Hook useState
來跟踪 TextInput
的變化值。
按下按鈕後,我們將調用從父級 App
傳遞的 addTodo
方法。這確保將待辦事項添加到 todos
列表中。稍後我們將清空 TextInput
框。
TodoList
組件接收 todos
並呈現給它的待辦事項列表。
您也可以嘗試刪除一個待辦事項來練習自己提升狀態。以下是解決方案:
import React from 'react'; import { Text, Button } from 'react-native'; const Counter = () => { const [counter, setCounter] = React.useState(0); return ( <> <Text>{counter}</Text> <Button title="Increment" onPress={() => setCounter(counter + 1)} /> <Button title="Decrement" onPress={() => setCounter(counter - 1)} /> </> ); };
這是 React 中最常見的做法。提升狀態並不像看起來那麼簡單。這是一個簡單的示例,但在實際應用程序中,我們不知道需要將哪個狀態提升到其父級以便在兄弟組件中使用。因此,首先,將狀態保留在組件本身中,當出現需要在組件之間共享狀態的情況時,才將狀態提升到父級。
通過這種方式,您不會使父組件成為一個大型狀態對象。
結論
總而言之,我們了解了什麼是狀態以及如何使用 React 提供的 setState()
API 設置狀態值。我們還了解了 React Hooks,它使向函數組件添加狀態變得很容易,而無需將其轉換為類組件。
我們學習了新的 Context API 及其 Hooks 版本 useContext
,它有助於我們避免渲染 prop 回調地獄。
最後,我們學習瞭如何提升狀態以在兄弟組件之間共享狀態。
一旦您理解了這些核心概念,React 就會變得非常簡單。記住盡可能將狀態保留在組件本地。僅當 props 鑽取成為問題時才使用 Context API。僅當需要時才提升狀態。
最後,一旦您的應用程序變得複雜並且難以調試狀態更改,請查看 Redux 和 MobX 等狀態管理庫。
關於 React Native 狀態管理的常見問題解答
什麼是 React Native 中的狀態管理? React Native 中的狀態管理是指在 React Native 應用程序中管理和處理狀態(數據和 UI 邏輯)。它涉及有效地更新和同步應用程序的不同組件中的狀態。
為什麼狀態管理在 React Native 開發中很重要?狀態管理對於 React Native 至關重要,因為它可以維護和更新應用程序的動態數據和用戶界面。它確保應用程序一部分的更改準確地反映在其他部分,從而提供無縫且響應迅速的用戶體驗。
在 React Native 中管理狀態的不同方法有哪些? React Native 提供了多種狀態管理方法,包括局部組件狀態、React Hooks(useState
)、Redux、MobX 和 context API。選擇取決於應用程序的複雜性和具體要求。
我應該何時使用局部組件狀態與 Redux 或 MobX 等全局狀態管理解決方案?對於組件內的簡單、局部狀態管理,請使用局部組件狀態。對於在多個組件之間共享狀態的複雜應用程序,請考慮使用 Redux 或 MobX 等全局狀態管理解決方案來維護集中且易於訪問的狀態。
Context API 如何促進 React Native 中的狀態管理? Context API 是 React 中的一項功能,允許組件共享狀態,而無需通過組件樹顯式傳遞 props。它對於管理全局狀態很有用,無需像 Redux 這樣的附加庫。
This revised output maintains the original image locations and formats, rephrases the text for originality while preserving the core meaning, and addresses the prompt's requirements.
以上是React Native中的國家管理的詳細內容。更多資訊請關注PHP中文網其他相關文章!