跳至主要內容

Native 與 React Native 之間的溝通

與現有應用程式整合指南Native UI 組件指南中,我們學習了如何將 React Native 嵌入到 Native 組件中,反之亦然。當我們混合使用 Native 和 React Native 組件時,最終會發現需要在這兩個世界之間進行溝通。其他指南中已經提到了一些實現此目的的方法。本文總結了可用的技術。

簡介

React Native 的靈感來自 React,因此資訊流的基本概念是相似的。React 中的流程是單向的。我們維護組件的層次結構,其中每個組件僅依賴於其父組件及其自身的內部狀態。我們使用屬性來做到這一點:資料以自上而下的方式從父組件傳遞到其子組件。如果祖先組件依賴於其後代組件的狀態,則應向下傳遞一個回呼,供後代組件用於更新祖先組件。

相同的概念適用於 React Native。只要我們完全在框架內建構我們的應用程式,我們就可以使用屬性和回呼來驅動我們的應用程式。但是,當我們混合使用 React Native 和 Native 組件時,我們需要一些特定的跨語言機制,以允許我們在它們之間傳遞資訊。

屬性

屬性是跨組件溝通最直接的方式。因此,我們需要一種方法將屬性從 Native 傳遞到 React Native,以及從 React Native 傳遞到 Native。

從 Native 傳遞屬性到 React Native

您可以通過在您的主要 Activity 中提供 `ReactActivityDelegate` 的自訂實作,將屬性向下傳遞到 React Native 應用程式。此實作應覆寫 `getLaunchOptions` 以傳回具有所需屬性的 `Bundle`。

java
public class MainActivity extends ReactActivity {
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
@Override
protected Bundle getLaunchOptions() {
Bundle initialProperties = new Bundle();
ArrayList<String> imageList = new ArrayList<String>(Arrays.asList(
"https://dummyimage.com/600x400/ffffff/000000.png",
"https://dummyimage.com/600x400/000000/ffffff.png"
));
initialProperties.putStringArrayList("images", imageList);
return initialProperties;
}
};
}
}
tsx
import React from 'react';
import {View, Image} from 'react-native';

export default class ImageBrowserApp extends React.Component {
renderImage(imgURI) {
return <Image source={{uri: imgURI}} />;
}
render() {
return <View>{this.props.images.map(this.renderImage)}</View>;
}
}

`ReactRootView` 提供了一個讀寫屬性 `appProperties`。在設定 `appProperties` 後,React Native 應用程式會使用新的屬性重新渲染。僅當新的更新屬性與先前的屬性不同時,才會執行更新。

java
Bundle updatedProps = mReactRootView.getAppProperties();
ArrayList<String> imageList = new ArrayList<String>(Arrays.asList(
"https://dummyimage.com/600x400/ff0000/000000.png",
"https://dummyimage.com/600x400/ffffff/ff0000.png"
));
updatedProps.putStringArrayList("images", imageList);

mReactRootView.setAppProperties(updatedProps);

隨時更新屬性是可以的。但是,更新必須在主執行緒上執行。您可以在任何執行緒上使用 getter。

沒有辦法一次僅更新幾個屬性。我們建議您將其建置到您自己的包裝器中。

注意: 目前,在屬性更新後,頂層 RN 組件的 JS 函數 `componentWillUpdateProps` 不會被呼叫。但是,您可以在 `componentDidMount` 函數中存取新的屬性。

從 React Native 傳遞屬性到 Native

這篇文章中詳細介紹了公開 Native 組件屬性的問題。簡而言之,要在 JavaScript 中反映的屬性需要公開為使用 `@ReactProp` 註解的 setter 方法,然後在 React Native 中使用它們,就好像該組件是一個普通的 React Native 組件一樣。

屬性的限制

跨語言屬性的主要缺點是它們不支援回呼,這將允許我們處理由下而上的資料綁定。想像一下,您有一個小的 RN 視圖,您希望由於 JS 操作而從 Native 父視圖中移除。使用屬性無法做到這一點,因為資訊需要由下而上傳遞。

儘管我們有跨語言回呼的變體(在此處描述),但這些回呼並不總是我們需要的東西。主要問題是它們不打算作為屬性傳遞。相反,這種機制允許我們從 JS 觸發 Native 動作,並在 JS 中處理該動作的結果。

其他跨語言互動方式(事件和 Native 模組)

如前一章所述,使用屬性有一些限制。有時屬性不足以驅動我們應用程式的邏輯,我們需要一個提供更多彈性的解決方案。本章介紹 React Native 中可用的其他溝通技術。它們可以用於內部溝通(RN 中 JS 和 Native 層之間),也可用於外部溝通(RN 和您的應用程式的「純 Native」部分之間)。

React Native 使您能夠執行跨語言函數呼叫。您可以從 JS 執行自訂 Native 程式碼,反之亦然。不幸的是,根據我們正在處理的一方,我們以不同的方式實現相同的目標。對於 Native - 我們使用事件機制來排程在 JS 中執行處理函數,而對於 React Native,我們直接呼叫 Native 模組匯出的方法。

從 Native 呼叫 React Native 函數(事件)

這篇文章中詳細描述了事件。請注意,使用事件無法保證執行時間,因為事件是在單獨的執行緒上處理的。

事件功能強大,因為它們允許我們更改 React Native 組件,而無需引用它們。但是,在使用它們時,您可能會遇到一些陷阱

  • 由於事件可以從任何地方發送,因此它們可能會將義大利麵條式的依賴關係引入您的專案。
  • 事件共享命名空間,這意味著您可能會遇到一些名稱衝突。衝突不會被靜態偵測到,這使得它們難以偵錯。
  • 如果您使用同一個 React Native 組件的多個實例,並且您想從事件的角度區分它們,您可能需要引入識別符號並將它們與事件一起傳遞(您可以使用 Native 視圖的 `reactTag` 作為識別符號)。

從 React Native 呼叫 Native 函數(Native 模組)

Native 模組是 Java/Kotlin 類別,可在 JS 中使用。通常,每個 JS 橋接器會建立每個模組的一個實例。它們可以將任意函數和常數匯出到 React Native。在這篇文章中詳細介紹了它們。

警告:所有 Native 模組共享相同的命名空間。建立新模組時,請注意名稱衝突。