8、状态管理入门:remember 与 mutableStateOf、状态提升的概念
状态管理,说白了就是解决「数据变了,UI 怎么跟着变」的问题。
我记得刚接触 Compose 时,最让我困惑的就是:明明变量改了,界面怎么没反应?后来才明白,Compose 不是靠「监听变量变化」来刷新 UI 的,它有一套自己的规则。今天我们就从最基础的两个工具讲起——remember 和 mutableStateOf,再聊聊「状态提升」这个设计思路。
8.1 为什么需要 remember?
先看一个简单的例子:
@Composable
fun Counter() {
var count = 0
Button(onClick = { count++ }) {
Text("点击了 $count 次")
}
}
你猜结果会怎样?
点击按钮,count 确实加了 1,但界面上的数字纹丝不动。为什么?
因为 Compose 函数在执行时,var count = 0 会被重新初始化。每次重组(Recomposition),count 都变回 0。你想想看,这就像每次开会都重新发一张白纸,之前写的内容全没了。
这时候就需要 remember 登场了。
核心理解:remember 的作用是「记住」某个值,让它在重组时不被重置。
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("点击了 $count 次")
}
}
加上 remember 之后,count 的值就能跨重组保留了。点击按钮,数字乖乖地加 1。
嗯,这里要注意:remember 只在当前 Composable 的生命周期内有效。如果这个 Composable 被移出视图树(比如页面跳转),记住的值也就丢了。
8.2 mutableStateOf:让 Compose 知道「值变了」
光记住还不够。你还需要告诉 Compose:「这个值变了,你得刷新 UI」。
mutableStateOf 就是干这个的。它创建了一个「可观察的状态容器」。当容器的值发生变化时,Compose 会自动触发读取过这个状态的 Composable 重组。
我个人习惯把 remember 和 mutableStateOf 搭配使用,像这样:
@Composable
fun GreetingCard() {
var name by remember { mutableStateOf("") }
TextField(
value = name,
onValueChange = { name = it },
label = { Text("请输入姓名") }
)
Text("你好,$name!")
}
这里 name 变了,Text 会自动更新。整个过程不需要你手动调用任何刷新方法。
小技巧:用 by 委托可以少写 .value,代码更清爽。如果你看到 val state = remember { mutableStateOf(0) },那后面就得用 state.value 来读写。
8.3 状态提升:把数据「往上挪」
实际项目中,状态不会只在一个 Composable 里自娱自乐。多个组件之间需要共享数据,这时候就引出了「状态提升」的概念。
什么叫状态提升?说白了就是:把状态放到调用方去管理,子组件只负责展示和通知。
我在项目中遇到过这样一个场景:一个搜索框和一个搜索结果列表,它们需要共享同一个关键词。如果各自维护自己的状态,那搜索框输入了内容,列表根本不知道。
正确的做法是:
@Composable
fun SearchScreen() {
var query by remember { mutableStateOf("") }
SearchBar(
query = query,
onQueryChange = { query = it }
)
SearchResults(query = query)
}
@Composable
fun SearchBar(query: String, onQueryChange: (String) -> Unit) {
TextField(
value = query,
onValueChange = onQueryChange,
label = { Text("搜索") }
)
}
@Composable
fun SearchResults(query: String) {
// 根据 query 展示结果
Text("当前搜索:$query")
}
你看,query 状态被提升到了 SearchScreen 里。SearchBar 和 SearchResults 都不持有状态,它们只通过参数接收数据,通过回调通知变化。
避坑指南:我曾经把一个状态放在子组件里,结果父组件想读取时发现拿不到。后来才意识到,状态提升不只是「技术选择」,更是「架构设计」。原则很简单:谁需要这个状态,谁就持有它。如果多个组件需要,就提升到它们的共同父级。
8.4 状态提升的三大好处
| 好处 | 说明 |
|---|---|
| 可复用性 | 子组件不依赖具体状态,换到任何地方都能用 |
| 可测试性 | 状态逻辑集中在父组件,方便单独测试 |
| 数据流向清晰 | 数据从上往下流,事件从下往上流,一眼就能看懂 |
你想想看,如果每个组件都自己管状态,那调试起来就像在迷宫里找出口。状态提升之后,数据流变成了一条直线,出问题很快就能定位。
8.5 本章知识体系
下面这张图帮你理清今天讲的核心逻辑:
8.6 避坑总结
最后分享几个我踩过的坑:
- 别在 remember 里放复杂计算——它每次重组都会执行 lambda。如果计算很重,用
remember(keys)指定依赖。 - 状态提升别过度——如果一个状态只有子组件自己用,没必要硬提到父级。保持简单。
- 小心「状态爆炸」——如果一个 Composable 有十几个状态参数,说明该拆分了。我见过一个页面传了 20 多个参数,改起来想哭。
好了,今天的内容就到这里。记住三个关键词:remember 保活、mutableStateOf 可观察、状态提升定层级。把这套组合拳打熟练了,Compose 的状态管理你就入门了。
公众号:蓝海资料掘金营,微信 deep3321