backdrop
指南

受控状态

如何在 Reka UI 中处理受控与非受控状态。

Reka UI 为组件提供了灵活的状态管理方案,允许开发者使用受控非受控状态。理解何时采用何种方式能确保与 Vue 响应式系统的更好集成。


受控与非受控状态

受控状态

受控组件通过 prop 接收其状态,并需要通过事件监听器显式更新状态。父组件负责管理并同步状态。

示例:受控 SwitchRoot

vue
<script setup>
import { SwitchRoot, SwitchThumb } from 'reka-ui'
import { ref } from 'vue'

const isActive = ref(false)

function handleUpdate(value) {
  isActive.value = value
}
</script>

<template>
  <SwitchRoot :model-value="isActive" @update:model-value="handleUpdate">
    <SwitchThumb />
  </SwitchRoot>
</template>

工作原理:

  • SwitchRoot 组件的状态由 isActive ref 管理。
  • @update:modelValue 事件确保更新正确传播。
以下情况使用受控状态:
  • 需要与 Vuex、Pinia 或 API 同步状态时。
  • 多个组件依赖同一状态时。
  • 需要对更新进行精细控制时。

对受控组件使用 v-model

Vue 的 v-model 语法为绑定 Reka UI 受控组件的值提供了便捷方式,它能自动处理值的传递与更新监听。

示例:对 SwitchRoot 使用 v-model

vue
<script setup>
import { SwitchRoot, SwitchThumb } from 'reka-ui'
import { ref } from 'vue'

const isActive = ref(false)
</script>

<template>
  <SwitchRoot v-model="isActive">
    <SwitchThumb />
  </SwitchRoot>
</template>

非受控状态

非受控组件在内部管理自身状态,无需依赖父组件控制的 prop。Reka UI 组件使用 defaultValue 而非 modelValue 来初始化状态。

示例:非受控 SwitchRoot

vue
<template>
  <SwitchRoot default-value="true">
    <SwitchThumb />
  </SwitchRoot>
</template>

工作原理:

  • SwitchRoot 使用 defaultValue 初始化其状态。
  • 状态变化在内部发生,无需外部控制。
以下情况使用非受控状态:
  • 组件无需与外部逻辑同步时。
  • 希望简化配置,无需显式状态管理时。
  • 状态仅为局部使用,不影响其他组件时。

常见错误与修复

1. 遗漏 @update:modelValue

vue
<!-- ❌ 错误: -->
<SwitchRoot :modelValue="isActive" />

<!-- ✅ 正确: -->
<SwitchRoot :modelValue="isActive" @update:modelValue="(val) => isActive = val" />

2. 误用 modelValue 替代 defaultValue

vue
<!-- ❌ 错误: -->
<SwitchRoot :modelValue="true" />

<!-- ✅ 正确: -->
<SwitchRoot defaultValue="true" />

3. 未为计算属性提供 setter

ts
// ❌ 错误:
const isActive = computed(() => store.state.toggleState)

// ✅ 正确:
const isActive = computed({
  get: () => store.state.toggleState,
  set: val => store.commit('setToggleState', val)
})