跳至主要内容

直接操作

有时需要直接对组件进行更改,而无需使用状态/属性来触发整个子树的重新渲染。例如,在浏览器中使用 React 时,有时需要直接修改 DOM 节点,移动应用中的视图也是如此。setNativeProps 是 React Native 中直接设置 DOM 节点属性的等效方法。

注意

当频繁重新渲染导致性能瓶颈时使用 setNativeProps

直接操作不是您经常使用的工具。您通常仅将其用于创建连续动画,以避免渲染组件层次结构和协调许多视图的开销。setNativeProps 是命令式的,它将状态存储在原生层(DOM、UIView 等)中,而不是在您的 React 组件中,这使得您的代码更难以理解。

在使用它之前,请尝试使用 setStateshouldComponentUpdate 解决您的问题。

使用 TouchableOpacity 的 setNativeProps

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

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

这允许我们编写以下代码,并知道子组件将在响应点击时更新其不透明度,而子组件无需了解此事实或对其实现进行任何更改

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

假设 setNativeProps 不可用。一种在该约束下实现它的方法是将不透明度值存储在状态中,然后在每次触发 onPress 时更新该值

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 子组件必须是原生组件或将 setNativeProps 转发给原生组件。发生这种情况是因为 MyButton 没有直接由一个应该设置其不透明度的原生视图支持。您可以这样理解:如果您使用 createReactClass 定义一个组件,您不会期望能够在其上设置样式属性并使其生效 - 您需要将样式属性传递给子组件,除非您正在包装一个原生组件。类似地,我们将把 setNativeProps 转发给一个原生支持的子组件。

将 setNativeProps 转发给子组件

由于 setNativeProps 方法存在于任何对 View 组件的引用上,因此只需将自定义组件上的引用转发到其渲染的 <View /> 组件之一即可。这意味着对自定义组件上的 setNativeProps 的调用将与您对包装的 View 组件本身调用 setNativeProps 具有相同的效果。

您现在可以在 TouchableOpacity 内部使用 MyButton 了!

您可能已经注意到,我们使用 {...props} 将所有属性传递给子视图。这样做的原因是 TouchableOpacity 实际上是一个复合组件,因此除了依赖于其子组件上的 setNativeProps 之外,它还需要子组件执行触摸处理。为此,它传递了 各种属性,这些属性回调到 TouchableOpacity 组件。相比之下,TouchableHighlight 由原生视图支持,并且只需要我们实现 setNativeProps

使用 setNativeProps 编辑 TextInput 值

setNativeProps 的另一个非常常见的用例是编辑 TextInput 的值。TextInput 的 controlled 属性在 bufferDelay 很低且用户输入速度非常快时有时会丢失字符。一些开发人员更喜欢完全跳过此属性,而是在必要时使用 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() 相反。