在原生和React Native间通信
本文档贡献者:sunnylqm(100.00%)
原文链接地址
通过植入原生应用和原生 UI 组件两篇文档,我们学习了 React Native 和原生组件的互相整合。在整合的过程中,我们会需要在两个世界间互相通信。有些方法已经在其他的指南中提到了,这篇文章总结了所有可行的技术。
简介
React Native 是从 React 中得到的灵感,因此基本的信息流是类似的。在 React 中信息是单向的。我们维护着组件层次,在其中每个组件都仅依赖于它父组件和自己的状态。通过属性(props)我们将信息从上而下的从父组件传递到子元素。如果一个祖先组件需要自己子孙的状态,推荐的方法是传递一个回调函数给对应的子元素。
React Native 也运用了相同的概念。只要我们完全在框架内构建应用,就可以通过属性和回调函数来调动整个应用。但是,当我们混合 React Native 和原生组件时,我们需要一些特殊的,跨语言的机制来传递信息。
属性
属性是最简单的跨组件通信。因此我们需要一个方法从原生组件传递属性到 React Native 或者从 React Native 到原生组件。
从原生组件传递属性到 React Native
我们使用RCTRootView将 React Natvie 视图封装到原生组件中。RCTRootView是一个UIView容器,承载着 React Native 应用。同时它也提供了一个联通原生端和被托管端的接口。
通过RCTRootView的初始化函数你可以将任意属性传递给 React Native 应用。参数initialProperties必须是NSDictionary的一个实例。这一字典参数会在内部被转化为一个可供 JS 组件调用的 JSON 对象。
NSArray *imageList = @[@”http://foo.com/bar1.png“,
@”http://foo.com/bar2.png“];
NSDictionary *props = @{@”images” : imageList};
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@”ImageBrowserApp”
initialProperties:props];
import React from ‘react’;
import {
AppRegistry,
View,
Image
} from ‘react-native’;
class ImageBrowserApp extends React.Component {
renderImage(imgURI) {
return (
pragma mark - RCTRootViewDelegate
(void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView
{
CGRect newFrame = rootView.frame;
newFrame.size = rootView.intrinsicContentSize;rootView.frame = newFrame;
}
在例子中我们使用一个FlexibleSizeExampleView视图来包含根视图。我们创建了根视图,初始化并且设置了代理。代理将会处理尺寸更新。然后,我们设置根视图的弹性尺寸为RCTRootViewSizeFlexibilityHeight,意味着rootViewDidChangeIntrinsicSize:方法将会在每次 React Native 内容高度变化时进行调用。最后,我们设置根视图的宽度和位置。注意我们也设置了高度,但是并没有效果,因为我们已经将高度设置为根据 RN 内容进行弹性变化了。
你可以在这里查看完整的例子源代码。
动态改变根视图的弹性模式是可行的。改变根视图的弹性模式将会导致布局的重新计算,并且在重新量出内容尺寸时会调用rootViewDidChangeIntrinsicSize方法。
注意: React Native 布局是通过一个特殊的线程进行计算,而原生 UI 视图是通过主线程更新。这可能导致短暂的原生端和 React Native 端的不一致。这是一个已知的问题,我们的团队已经在着手解决不同源的 UI 同步更新。 注意: 除非根视图成为其他视图的子视图,否则 React Native 不会进行任何的布局计算。如果你想在还没有获得 React Native 视图的尺寸之前先隐藏视图,请将根视图添加为子视图并且在初始化的时候进行隐藏(使用UIView的hidden属性),然后在代理方法中改变它的可见性。