This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

useNativeState

一个 React 钩子,用于创建在 JavaScript 和原生 SwiftUI 视图之间共享的可观察状态。

iOS
tvOS
Included in Expo Go
Recommended version:
~57.0.3

useNativeState 返回一个 ObservableState,它在原生端映射到 SwiftUI 的 ObservableObject,因此对 .value 的读取和写入会被 SwiftUI 直接观察,而无需经过 React 渲染周期。这使你可以从 UI 线程上的工作单元同步更新原生视图。

注意: 在使用 React 编译器 时,你应该避免直接访问和修改 value 属性。相反,应使用符合 React 编译器标准的 getset 方法。

安装

🌐 Installation

Terminal
npx expo install @expo/ui

If you are installing this in an existing React Native app, make sure to install expo in your project.

用法

🌐 Usage

注意: 使用 worklets 需要在你的项目中安装 react-native-workletsuseNativeState 本身可以在没有它的情况下工作,但下面显示的同步 UI 线程更新依赖于 worklet 运行时。

下面的示例在用户输入时会对电话号码进行屏蔽。格式化和对 maskedPhone.value(文本)以及 selection.value(光标位置)的写入都在 UI 线程上同步进行,因此在输入值和屏蔽值之间不会出现闪烁。

🌐 The example below masks a phone number as the user types. The formatting and the writes to maskedPhone.value (text) and selection.value (cursor position) all happen synchronously on the UI thread, so there is no flicker between the typed value and the masked value.

WorkletPhoneMaskExample.tsx
import { Host, TextField, useNativeState } from '@expo/ui/swift-ui'; import { keyboardType } from '@expo/ui/swift-ui/modifiers'; import { useEffectEvent } from 'react'; export default function WorkletPhoneMaskExample() { const maskedPhone = useNativeState(''); const selection = useNativeState({ start: 0, end: 0 }); const handleTextChange = useEffectEvent((v: string) => { 'worklet'; const digits = v.replace(/\D/g, '').slice(0, 10); let formatted: string; if (digits.length === 0) { formatted = ''; } else if (digits.length <= 3) { formatted = digits; } else if (digits.length <= 6) { formatted = `(${digits.slice(0, 3)}) ${digits.slice(3)}`; } else { formatted = `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`; } if (formatted !== v) { maskedPhone.value = formatted; // Snaps to end for demo. Real masks need smarter cursor handling. selection.value = { start: formatted.length, end: formatted.length }; } }); return ( <Host matchContents> <TextField text={maskedPhone} selection={selection} placeholder="(555) 123-4567" modifiers={[keyboardType('phone-pad')]} onTextChange={handleTextChange} /> </Host> ); }

应用接口

🌐 API

import { useNativeState } from '@expo/ui/swift-ui';

Hooks

useNativeState(initialValue)

ParameterType
initialValueT

Creates an observable native state that is automatically cleaned up when the component unmounts. initialValue is captured once on the first render

Returns:
ObservableState<T>

Types

ObservableState

Observable state shared between JavaScript and native views (Jetpack Compose on Android and SwiftUI on iOS).

Type: SharedObject extended by:

PropertyTypeDescription
onChange[listener] | null

A single listener invoked on the native UI runtime whenever the value changes (after iOS didSet and Android's setter). Assigning replaces the previous listener; assign null to clear. The initial value does not fire onChange.

The callback must be a worklet so it can run synchronously on the UI thread. Attach it inside useEffect and clear it in the cleanup so the listener lifecycle matches the component lifecycle.

Example

const state = useNativeState(0); useEffect(() => { state.onChange = (value) => { 'worklet'; console.log('changed to', value); }; }, []);
valueT

The current value.

Writes from a UI worklet are synchronous and immediately readable. Writes from the JS thread are scheduled to the UI thread asynchronously, the new value is not readable until the update has been applied. Prefer writing from a worklet when you need synchronous updates

get() => T

Reads the current value. A React Compiler compliant alternative to reading .value

set(value: T) => void

Writes a new value. A React Compiler-compliant alternative to assigning .value