前言
在传统的移动端开发中,页面的展示和数据是分开管理的。比如在 iOS 中如果我们要显示一个标题的话,会使用下面这种命令式 UI 的方式去实现,如 UIKit
中的控件:
ini
// 先设置 UILabel 的样式
let titleLabel = UILabel(frame: .zero)
titleLabel.textColor = .black
self.titleLabel = titleLabel
// 然后加载完数据之后,再去设置内容
self.titleLabel.text = mode.title
这样实现存在一个问题就是代码分离,实现完控件之后我们还需要等网络数据回来之后再去修改控件的展示。
使用了状态管理的声明式 UI 就解决了上面存在的问题。我们只负责实现完控件之后将其和状态管理的变量绑定,之后我们只需要操作状态管理的变量即可,控件的样式会自动去更新。在 React Native 中,useState
就是来进行状态管理的。
首先,我们来看下它是如何使用的。
useState 的使用
第一步,我们需要导入 React 来使用 useState:
javascript
import { useState } from 'react';
接下来,在自定义的组件中去使用它:
javascript
export default function Counter() {
const [counter, setCounter] = useState(1);
function counterIncreate() {
setCounter(counter + 1);
}
return (
<>
<View style={{ width: '100%', height: '200rpx' }}>
<Text style={{ width: '100rpx', height: '30rpx' }}>{`数量:${counter}`} </Text>
<TouchableOpacity style={{ width: '100rpx', height: '60rpx' }} onPress={() => counterIncreate()}>
<Text style={{ width: '50rpx', height: '30rpx' }}>增加</Text>
</TouchableOpacity>
</View>
</>
);
}
上面的代码绘制了两个组件,一个是显示当前数量的文本组件,一个是增加数量的按钮组件。然后声明了一个 counterIncreate()
函数用来更新 counter
的值。 最后将 counter
变量与显示数量的文本组件进行绑定。
核心代码就是下面的这两行:
scss
// 组件与变量进行绑定
<Text style={{ width: '100rpx', height: '30rpx' }}>{`数量:${counter}`} </Text>
// 点击按钮的时候去修改状态变量
setCounter(counter + 1);
上面的代码运行之后,点击增加按钮,数量加1之后会自动进行渲染。
useState 函数
scss
const [counter, setCounter] = useState(1);
通过上面的代码可以看到,useState()
接受一个任意类型的初始值,然后返回一个数组。数组包含一个状态变量,变量的初始值是函数传进去的初始值;一个状态变量对应的 set 函数。关于数组内的命名约定俗成的格式是下面这种格式:
-
xxx, setXxx\] xxx 为变量名。
scss
// set 命名为 setCounter1
const [counter, setCounter1] = useState(1);
function counterIncreate() {
setCounter1(counter + 1);
}
但建议还是按照约定俗成的格式去命名。
数据的不变性
对与状态变量,是有不可变性的。我们只能通过返回的 set 函数去修改它的值。我们需要使用 const
去修饰。我们不能通过直接修改状态变量的值去更新渲染组件。比如下面的代码:
scss
const [counter, setCounter] = useState(1);
function counterIncreate() {
// 报错,因为 counter 是不可变的。
counter = counter + 1;
}
即使我们用 let
修饰,虽然不会报错,但也无法进行组件状态的更新:
ini
let [counter, setCounter] = useState(1);
function counterIncreate() {
counter = counter + 1;
}
原因是 React Native 是在返回的 setState 函数中去处理状态更新的相关逻辑,所以 counter = counter + 1
是无法触发组件的状态更新。
如何获取当前的状态值
如果我们的需求是在更新状态的同时还要记录下当前的状态值,那么需要像下面这种方式去获取:
ini
function counterIncreate() {
// counter = 1
setCounter(counter + 1);
const result = counter + 1;
console.log(result); // 2
}
如果我们这样写是无法正确的获取当前状态值的:
ini
function counterIncreate() {
// counter = 1
setCounter(counter + 1);
const result = counter;
console.log(result); // 1
}
因为 counter 更像是保存的一份快照,我们调用 setCounter()
函数的时候并不会去更新 counter 的值,所以这种方式是不能正确获取的。