跳至主内容
版本:当前版本

直接操作

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

有时需要直接修改组件而不通过状态/属性触发整个子树重新渲染。例如在浏览器中使用 React 时,你可能需要直接修改 DOM 节点,在移动应用中操作视图也是同样的道理。setNativeProps 就是 React Native 中直接设置 DOM 节点属性的等效方法。

注意

仅在频繁重渲染导致性能瓶颈时使用 setNativeProps

直接操作不应成为常用工具。通常只在创建连续动画时使用,以避免渲染组件树和协调多个视图的开销。 setNativeProps 是命令式的,它将状态存储在原生层(DOM、UIView 等)而非 React 组件中,这会增加代码的理解难度。

在使用前,请先尝试用 setStateshouldComponentUpdate 解决问题。

TouchableOpacity 中的 setNativeProps

TouchableOpacity 在内部使用 setNativeProps 更新其子组件的不透明度:

tsx
const viewRef = useRef<View>();
const setOpacityTo = useCallback(value => {
// Redacted: animation related code
viewRef.current.setNativeProps({
opacity: value,
});
}, []);

这样我们可以编写以下代码,确保子组件会在点击时更新不透明度,而子组件无需知晓这个逻辑,也不需要修改其实现:

tsx
<TouchableOpacity onPress={handlePress}>
<View>
<Text>Press me!</Text>
</View>
</TouchableOpacity>

假设 setNativeProps 不可用。在这种限制下,我们可以将不透明度值存储在状态中,然后在触发 onPress 时更新该值:

tsx
const [buttonOpacity, setButtonOpacity] = useState(1);
return (
<TouchableOpacity
onPressIn={() => setButtonOpacity(0.5)}
onPressOut={() => setButtonOpacity(1)}>
<View style={{opacity: buttonOpacity}}>
<Text>Press me!</Text>
</View>
</TouchableOpacity>
);

相比原始方案,这种方式计算开销更大——即使视图及其子组件的其他属性未改变,React 也需要在每次不透明度变化时重新渲染整个组件树。通常这种开销无关紧要,但在执行连续动画和响应手势时,明智地优化组件可以提高动画的流畅度。

如果查看 NativeMethodsMixinsetNativeProps 的实现,你会发现它实际是 RCTUIManager.updateView 的封装——这与重渲染触发的函数调用完全相同(参见 ReactNativeBaseComponent 中的 receiveComponent)。

复合组件与 setNativeProps

复合组件没有对应的原生视图支撑,因此不能直接调用 setNativeProps。参考以下示例:

运行后会立即看到错误:Touchable child must either be native or forward setNativeProps to a native component。这是因为 MyButton 没有直接对应可设置不透明度的原生视图。可以这样理解:如果用 createReactClass 定义组件,你不会期望直接设置其样式属性就能生效——除非包装了原生组件,否则必须将样式属性传递给子组件。同理,我们需要将 setNativeProps 转发给原生支撑的子组件。

将 setNativeProps 转发给子组件

由于 setNativeProps 方法存在于任何指向 View 组件的引用上,只需将自定义组件的引用转发给它渲染的某个 <View /> 组件即可。这意味着在自定义组件上调用 setNativeProps 的效果等同于直接在被包装的 View 组件上调用 setNativeProps

现在你可以在 TouchableOpacity 中使用 MyButton 了!

您可能注意到我们使用 {...props} 将所有属性传递给了子视图。这是因为 TouchableOpacity 实际上是一个复合组件,除了依赖子组件的 setNativeProps 方法外,还需要子组件处理触摸事件。为此,它会传递多种属性来回调 TouchableOpacity 组件。相比之下,TouchableHighlight 由原生视图支持,仅要求我们实现 setNativeProps

使用 setNativeProps 编辑 TextInput 值

另一个常见的 setNativeProps 应用场景是编辑 TextInput 的值。当 bufferDelay 设置较低且用户输入极快时,TextInput 的 controlled 属性有时会丢失字符。部分开发者倾向于完全跳过该属性,转而使用 setNativeProps 在必要时直接操作 TextInput 值。例如,以下代码演示了点击按钮时编辑输入框:

您可以使用 clear 方法清除 TextInput,该方法采用相同方式清空当前输入文本。

避免与渲染函数冲突

若您更新的属性同时被渲染函数管理,可能导致不可预测的混乱错误。因为每当组件重新渲染且该属性变化时,先前通过 setNativeProps 设置的值会被完全忽略并覆盖。

setNativeProps 与 shouldComponentUpdate

通过合理运用 shouldComponentUpdate,您可以避免协调未变化的组件子树产生的额外开销。当性能足够时,完全可以用 setState 替代 setNativeProps

其他原生方法

本文描述的方法在 React Native 提供的大多数默认组件中可用。但请注意,这些方法_不适用于_未直接关联原生视图的复合组件(通常包括您自定义的大部分应用组件)。

measure(callback)

测量指定视图在屏幕中的位置、宽度和高度,并通过异步回调返回结果。测量成功后,回调参数包含:

  • x

  • y

  • width

  • height

  • pageX

  • pageY

注意:这些测量值需等待原生端渲染完成后才可用。若需尽快获取测量值且不需要 pageXpageY,建议改用 onLayout 属性。

另外 measure() 返回的宽高是组件在视窗中的尺寸。如需获取组件的实际尺寸,建议使用 onLayout 属性。

measureInWindow(callback)

测量指定视图在窗口中的位置,并通过异步回调返回结果。当 React 根视图嵌入其他原生视图时,此方法提供绝对坐标。测量成功后,回调参数包含:

  • x

  • y

  • width

  • height

measureLayout(relativeToNativeComponentRef, onSuccess, onFail)

功能类似 measure(),但测量的是相对于指定祖先视图(通过 relativeToNativeComponentRef 引用)的位置。返回的坐标值相对于祖先视图原点的 xy 坐标。

:::注意 此方法也可通过 relativeToNativeNode 处理程序(而非引用)调用,但在新架构中该变体已废弃。 :::

focus()

为指定输入框或视图请求焦点。具体触发行为取决于平台和视图类型。

blur()

移除输入框或视图的焦点。这是 focus() 的反向操作。