核心要点
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中文网其他相关文章!