恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
【Jetpack Compose基础语法学与练】第5课 状态提升,把状态抽到父组件,实现组件解耦复用
首页
资讯中心
/
【Jetpack Compose基础语法学与练】第5课 状态提升,把状态抽到父组件,实现组件解耦复用
【Jetpack Compose基础语法学与练】第5课 状态提升,把状态抽到父组件,实现组件解耦复用
发布时间:2026/10/9 7:43:24
前言上一课学习了Modifier修饰器掌握尺寸、背景、内边距样式。前面我们把 remember 状态写在同一个页面组件里组件内部自己持有状态。但真实开发中组件需要复用、状态需要多个子组件共享。状态提升State Hoisting就是把状态从子组件提取到上层父组件子组件只负责UI展示不保存状态接收参数和回调。核心思想状态上移子组件无状态只接收数据回调。前置完成1~4课掌握remember、可组合函数、基础布局一、完整可运行示例源码packagecom.example.composefirstimportandroid.os.Bundleimportandroidx.activity.ComponentActivityimportandroidx.activity.compose.setContentimportandroidx.compose.foundation.layout.Columnimportandroidx.compose.foundation.layout.paddingimportandroidx.compose.material3.Buttonimportandroidx.compose.material3.Textimportandroidx.compose.runtime.Composableimportandroidx.compose.runtime.getValueimportandroidx.compose.runtime.mutableIntStateOfimportandroidx.compose.runtime.rememberimportandroidx.compose.runtime.setValueimportandroidx.compose.ui.Modifierimportandroidx.compose.ui.tooling.preview.Previewimportandroidx.compose.ui.unit.dpclassMainActivity:ComponentActivity(){overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContent{ParentPage()}}}// 父组件持有状态ComposablefunParentPage(){// 状态提升到父组件父组件保存countvarcountbyremember{mutableIntStateOf(0)}Column(modifierModifier.padding(20.dp)){// 无状态子组件传入数据 回调函数CounterDisplay(countcount){count1}}}// 无状态子组件只接收参数不定义remember状态ComposablefunCounterDisplay(count:Int,onAddClick:()-Unit){Column{Text(text当前计数$count)Button(onClickonAddClick){Text(点击1)}}}PreviewComposablefunStateHoistingPreview(){ParentPage()}二、逐行代码解读状态提升是什么原来状态写在子组件 CounterDisplay 内部组件自己管自己的数据。现在状态放到上层父组件 ParentPage 。父组件用 remember 保存状态 count 父组件把 count 作为参数传给子组件单向数据流数据向下传递子组件点击按钮调用父传过来的回调 onAddClick 通知父组件修改状态事件向上传递。CounterDisplay(count: Int, onAddClick: () - Unit)这是无状态可组合函数内部没有 remember 。count: Int 纯展示数据只读onAddClick: () - Unit 点击回调Lambda子组件触发事件由父组件处理状态变更。重点子组件不能修改count只能通知父组件去修改。数据流规则向下父 → 子状态数据向上子 → 父点击、输入等事件回调单向数据流逻辑清晰方便复用、单元测试。复用优势演示如果页面放两个 CounterDisplay 共用同一个父状态两个组件会同步刷新CounterDisplay(countcount){count1}CounterDisplay(countcount){count1}点击任意按钮两处Text同时更新实现多组件共享状态。三、核心概念有状态组件 vs 无状态组件有状态组件内部包含 remember 自己保存状态适合简单独立页面复用性差。无状态组件不持有任何remember状态所有数据和回调都由外部传入推荐优先写无状态组件可复用、便于测试。状态提升适用场景多个UI组件共用一份状态组件需要抽离复用在多处调用状态需要由上层统一控制。四、综合练习题填空题将状态从子组件提取到父组件的技术叫做________。状态提升后子组件通过________接收上层传来的数据。子组件想要修改状态不能直接修改传入数据需要调用上层传入的________。答案与解析状态提升State Hoisting解析Compose官方推荐模式抽离状态到父组件。函数参数解析父组件把状态值作为参数传给子组件。回调函数解析子组件触发事件调用回调通知父组件修改状态。判断题状态提升后的子组件内部依然可以写remember保存状态。答案错误。理由状态提升目标是让子组件变成纯UI无状态组件不应该在子组件内继续存放业务状态。子组件可以直接修改传入的count参数。答案错误。理由count是普通只读参数单向数据流子组件无权修改只能通知父组件修改。状态提升可以实现多个子组件共享同一份状态。答案正确。理由父组件持有唯一状态多个子组件都引用这份状态状态变更全部同步刷新。简答题对比「子组件内部存状态」和「状态提升到父组件」两种写法状态提升的好处是什么参考答案子组件变成纯UI可在多个地方复用一份状态可以给多个子组件共享逻辑与UI分离更容易单元测试统一在父组件管理数据方便控制业务逻辑。代码实操题基于本课示例改造新增回调 onResetClick 父组件增加重置逻辑子组件增加重置按钮。写出完整的 CounterDisplay 函数和父组件调用代码。参考答案ComposablefunParentPage(){varcountbyremember{mutableIntStateOf(0)}Column(modifierModifier.padding(20.dp)){CounterDisplay(countcount,onAddClick{count1},onResetClick{count0})}}ComposablefunCounterDisplay(count:Int,onAddClick:()-Unit,onResetClick:()-Unit){Column{Text(text当前计数$count)Button(onClickonAddClick){Text(点击1)}Button(onClickonResetClick){Text(重置)}}}解析父组件持有状态新增重置回调传给子组件子组件增加重置按钮点击触发回调由父组件修改count归零。五、本课小结状态提升把状态从子组件抽到父组件单向数据流数据向下传事件回调向上传优先写无状态组件便于复用多个组件共享同一份状态适合表单、计数器等场景。下一课TextField文本输入字符串状态与输入交互。