跳到主要內容

29 篇標註「工程」的文章

檢視所有標籤

將 TypeScript 與 React Native 搭配使用

·8 分鐘閱讀
Ash Furrow
Artsy 的軟體工程師

JavaScript!我們都喜歡它。但我們有些人也喜歡型別。幸運的是,存在一些選項可以為 JavaScript 新增更強大的型別。我最喜歡的是 TypeScript,但 React Native 開箱即用地支援 Flow。您偏好哪個取決於個人喜好,它們各自有其在 JavaScript 中新增型別魔力的獨特方法。今天,我們將探討如何在 React Native 應用程式中使用 TypeScript。

這篇文章使用 Microsoft 的 TypeScript-React-Native-Starter 儲存庫作為指南。

更新:自此部落格文章撰寫以來,事情變得更加容易。您可以透過執行一個命令來取代此部落格文章中描述的所有設定

npx react-native init MyAwesomeProject --template react-native-template-typescript

然而,Babel 的 TypeScript 支援確實存在一些限制,上述部落格文章詳細介紹了這些限制。文章中概述的步驟仍然有效,而 Artsy 仍在使用 react-native-typescript-transformer 於生產環境中,但開始使用 React Native 和 TypeScript 最快的方式是使用上述命令。如果需要,您隨時可以稍後切換。

無論如何,玩得開心!原始部落格文章繼續如下。

先決條件

由於您可能在數個不同的平台上進行開發,並以數種不同類型的裝置為目標,因此基本設定可能很複雜。您應先確保您可以執行不含 TypeScript 的純 React Native 應用程式。請依照 React Native 網站上的說明開始。當您成功部署到裝置或模擬器後,您就可以開始 TypeScript React Native 應用程式了。

您還需要 Node.jsnpmYarn

初始化

一旦您嘗試建立一個普通的 React Native 專案骨架後,您就可以開始新增 TypeScript 了。讓我們繼續執行此操作。

react-native init MyAwesomeProject
cd MyAwesomeProject

新增 TypeScript

下一步是將 TypeScript 新增至您的專案。以下命令將會

  • 將 TypeScript 新增至您的專案
  • React Native TypeScript Transformer 新增至您的專案
  • 初始化一個空的 TypeScript 設定檔,我們接下來將進行設定
  • 新增一個空的 React Native TypeScript Transformer 設定檔,我們接下來將進行設定
  • 新增 React 和 React Native 的 型別定義

好的,讓我們繼續執行這些命令。

yarn add --dev typescript
yarn add --dev react-native-typescript-transformer
yarn tsc --init --pretty --jsx react
touch rn-cli.config.js
yarn add --dev @types/react @types/react-native

tsconfig.json 檔案包含 TypeScript 編譯器的所有設定。上述命令建立的預設值大致上都沒問題,但開啟檔案並取消註解以下行

{
/* Search the config file for the following line and uncomment it. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
}

rn-cli.config.js 包含 React Native TypeScript Transformer 的設定。開啟它並新增以下內容

module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
},
};

遷移至 TypeScript

將產生的 App.js__tests__/App.js 檔案重新命名為 App.tsxindex.js 需要使用 .js 副檔名。所有新檔案都應使用 .tsx 副檔名 (如果檔案不包含任何 JSX,則使用 .ts)。

如果您現在嘗試執行應用程式,您會收到類似 object prototype may only be an object or null 的錯誤。這是因為無法從 React 匯入預設匯出,以及在同一行上匯入具名匯出所導致的。開啟 App.tsx 並修改檔案頂端的匯入

-import React, { Component } from 'react';
+import React from 'react'
+import { Component } from 'react';

其中一些與 Babel 和 TypeScript 如何與 CommonJS 模組互動的差異有關。在未來,這兩者將在相同的行為上趨於穩定。

此時,您應該能夠執行 React Native 應用程式了。

新增 TypeScript 測試基礎架構

React Native 隨附 Jest,因此為了使用 TypeScript 測試 React Native 應用程式,我們會想要將 ts-jest 新增至我們的 devDependencies

yarn add --dev ts-jest

然後,我們將開啟我們的 package.json 並將 jest 欄位替換為以下內容

{
"jest": {
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"^.+\\.(js)$": "<rootDir>/node_modules/babel-jest",
"\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/"
],
"cacheDirectory": ".jest/cache"
}
}

這會將 Jest 設定為使用 ts-jest 執行 .ts.tsx 檔案。

安裝依賴項型別宣告

為了在 TypeScript 中獲得最佳體驗,我們希望型別檢查器能夠理解我們依賴項的形狀和 API。某些程式庫將發佈包含 .d.ts 檔案 (型別宣告/型別定義檔案) 的套件,這些檔案可以描述基礎 JavaScript 的形狀。對於其他程式庫,我們需要明確地在 @types/ npm 範圍中安裝適當的套件。

例如,在這裡我們需要 Jest、React、React Native 和 React Test Renderer 的型別。

yarn add --dev @types/jest @types/react @types/react-native @types/react-test-renderer

我們將這些宣告檔案套件儲存到我們的開發依賴項中,因為這是一個 React Native應用程式,僅在開發期間使用這些依賴項,而不是在執行階段使用。如果我們要將程式庫發佈到 NPM,我們可能必須將其中一些型別依賴項新增為常規依賴項。

您可以在 這裡 閱讀更多關於取得 .d.ts 檔案的資訊。

忽略更多檔案

對於您的原始碼控制,您會想要開始忽略 .jest 資料夾。如果您使用 git,我們只需將條目新增至我們的 .gitignore 檔案即可。

# Jest
#
.jest/

作為檢查點,請考慮將您的檔案提交到版本控制中。

git init
git add .gitignore # import to do this first, to ignore our files
git add .
git commit -am "Initial commit."

新增組件

讓我們將一個組件新增至我們的應用程式。讓我們繼續建立一個 Hello.tsx 組件。這是一個教學組件,不是您實際上會在應用程式中編寫的組件,而是一些非平凡的東西,展示如何在 React Native 中使用 TypeScript。

建立一個 components 目錄並新增以下範例。

// components/Hello.tsx
import React from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';

export interface Props {
name: string;
enthusiasmLevel?: number;
}

interface State {
enthusiasmLevel: number;
}

export class Hello extends React.Component<Props, State> {
constructor(props: Props) {
super(props);

if ((props.enthusiasmLevel || 0) <= 0) {
throw new Error(
'You could be a little more enthusiastic. :D',
);
}

this.state = {
enthusiasmLevel: props.enthusiasmLevel || 1,
};
}

onIncrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel + 1,
});
onDecrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel - 1,
});
getExclamationMarks = (numChars: number) =>
Array(numChars + 1).join('!');

render() {
return (
<View style={styles.root}>
<Text style={styles.greeting}>
Hello{' '}
{this.props.name +
this.getExclamationMarks(this.state.enthusiasmLevel)}
</Text>

<View style={styles.buttons}>
<View style={styles.button}>
<Button
title="-"
onPress={this.onDecrement}
accessibilityLabel="decrement"
color="red"
/>
</View>

<View style={styles.button}>
<Button
title="+"
onPress={this.onIncrement}
accessibilityLabel="increment"
color="blue"
/>
</View>
</View>
</View>
);
}
}

// styles
const styles = StyleSheet.create({
root: {
alignItems: 'center',
alignSelf: 'center',
},
buttons: {
flexDirection: 'row',
minHeight: 70,
alignItems: 'stretch',
alignSelf: 'center',
borderWidth: 5,
},
button: {
flex: 1,
paddingVertical: 0,
},
greeting: {
color: '#999',
fontWeight: 'bold',
},
});

哇!這很多,但讓我們分解一下

  • 我們不是像 divspanh1 等那樣呈現 HTML 元素,而是呈現像 ViewButton 這樣的組件。這些是在不同平台上運作的原生組件。
  • 樣式是使用 React Native 給我們的 StyleSheet.create 函式指定的。React 的樣式表允許我們使用 Flexbox 控制我們的版面配置,並使用其他類似於 CSS 中的結構來設定樣式。

新增組件測試

現在我們有了一個組件,讓我們嘗試測試它。

我們已經安裝了 Jest 作為測試執行器。我們將為我們的組件編寫快照測試,讓我們為快照測試新增所需的附加元件

yarn add --dev react-addons-test-utils

現在讓我們在 components 目錄中建立一個 __tests__ 資料夾,並為 Hello.tsx 新增一個測試

// components/__tests__/Hello.tsx
import React from 'react';
import renderer from 'react-test-renderer';

import {Hello} from '../Hello';

it('renders correctly with defaults', () => {
const button = renderer
.create(<Hello name="World" enthusiasmLevel={1} />)
.toJSON();
expect(button).toMatchSnapshot();
});

第一次執行測試時,它將建立呈現組件的快照,並將其儲存在 components/__tests__/__snapshots__/Hello.tsx.snap 檔案中。當您修改組件時,您需要更新快照並檢查更新是否有意外的變更。您可以在 這裡 閱讀更多關於測試 React Native 組件的資訊。

後續步驟

查看官方 React 教學課程 和狀態管理程式庫 Redux。這些資源在編寫 React Native 應用程式時可能會有所幫助。此外,您可能想看看 ReactXP,這是一個完全以 TypeScript 編寫的組件程式庫,同時支援 Web 上的 React 和 React Native。

在更具型別安全性的 React Native 開發環境中享受樂趣!

為 React Native 建置 <InputAccessoryView>

·6 分鐘閱讀
Peter Argany
Facebook 的軟體工程師

動機

三年前,開啟了一個 GitHub 議題,以支援來自 React Native 的輸入輔助視圖。

在隨後的幾年中,出現了無數的「+1」回應、各種變通方法,以及針對此議題的 RN 零具體變更 - 直到今天。從 iOS 開始,我們正在公開一個 API 以存取原生輸入輔助視圖,我們很高興分享我們是如何建置它的。

背景

輸入輔助視圖到底是什麼?閱讀 Apple 的開發人員文件,我們了解到它是一個自訂視圖,每當接收器成為第一響應者時,都可以錨定到系統鍵盤的頂部。任何繼承自 UIResponder 的物件都可以將 .inputAccessoryView 屬性重新宣告為讀寫,並在此處管理自訂視圖。響應者基礎架構會掛載視圖,並使其與系統鍵盤保持同步。解除鍵盤的手勢 (如拖曳或點擊) 會在框架層級套用至輸入輔助視圖。這讓我們能夠建置具有互動式鍵盤解除功能的內容,這是頂級訊息應用程式 (如 iMessage 和 WhatsApp) 中不可或缺的功能。

將視圖錨定到鍵盤頂部有兩種常見的用例。第一種是建立鍵盤工具列,如 Facebook 作曲家背景選擇器。

在這種情況下,鍵盤的焦點集中在文字輸入欄位上,而輸入輔助視圖則用於提供額外的鍵盤功能。此功能與輸入欄位的類型相關。在對應應用程式中,它可以是地址建議,或在文字編輯器中,它可以是 RTF 格式工具。


在此情況下,擁有 <InputAccessoryView> 的 Objective-C UIResponder 應該很清楚。<TextInput> 已成為第一響應者,而在底層,這會變成 UITextViewUITextField 的執行個體。

第二種常見情況是黏性文字輸入

在這裡,文字輸入實際上是輸入輔助視圖本身的一部分。這通常用於訊息應用程式中,在其中可以撰寫訊息,同時捲動瀏覽先前的訊息串。


在此範例中,誰擁有 <InputAccessoryView>?它可以再次是 UITextViewUITextField 嗎?文字輸入位於輸入輔助視圖內,這聽起來像是循環依賴。僅僅解決這個問題本身就是另一篇 部落格文章。劇透:擁有者是一個通用的 UIView 子類別,我們手動告訴它 becomeFirstResponder

API 設計

我們現在知道 <InputAccessoryView> 是什麼,以及我們想要如何使用它。下一步是設計一個對兩種用例都有意義,並且可以與現有的 React Native 組件 (如 <TextInput>) 良好協同運作的 API。

對於鍵盤工具列,我們需要考慮以下幾點

  1. 我們希望能夠將任何通用的 React Native 視圖階層結構提升到 <InputAccessoryView> 中。
  2. 我們希望這個通用的且分離的視圖階層結構能夠接受觸控並能夠操縱應用程式狀態。
  3. 我們希望將 <InputAccessoryView> 連結到特定的 <TextInput>
  4. 我們希望能夠在多個文字輸入之間共用 <InputAccessoryView>,而無需複製任何程式碼。

我們可以使用類似於 React portals 的概念來實現 #1。在這個設計中,我們將 React Native 視圖傳送到由響應者基礎架構管理的 UIView 階層結構。由於 React Native 視圖呈現為 UIView,因此這實際上非常簡單 - 我們可以覆寫

- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex

並將所有子視圖管道傳輸到新的 UIView 階層結構。對於 #2,我們為 <InputAccessoryView> 設定新的 RCTTouchHandler。狀態更新是透過使用常規事件回呼來實現的。對於 #3 和 #4,我們在建立 <TextInput> 組件期間,使用 nativeID 欄位在原生程式碼中找到輔助視圖 UIView 階層結構。此函式使用底層原生文字輸入的 .inputAccessoryView 屬性。這樣做有效地將 <InputAccessoryView> 連結到其 ObjC 實作中的 <TextInput>

支援黏性文字輸入 (情境 2) 新增了一些額外的限制。對於此設計,輸入輔助視圖具有作為子系的文字輸入,因此透過 nativeID 連結不是一個選項。相反地,我們將通用螢幕外 UIView.inputAccessoryView 設定為我們的原生 <InputAccessoryView> 階層結構。透過手動告訴這個通用 UIView 成為第一響應者,階層結構會由響應者基礎架構掛載。這個概念在前面提到的部落格文章中得到了詳盡的解釋。

陷阱

當然,在建置此 API 時並非一切都一帆風順。以下是我們遇到的一些陷阱,以及我們如何解決它們。

建置此 API 的最初想法涉及監聽 NSNotificationCenter 以取得 UIKeyboardWill(Show/Hide/ChangeFrame) 事件。此模式在某些開源程式庫以及 Facebook 應用程式的某些部分中內部使用。不幸的是,UIKeyboardDidChangeFrame 事件未及時呼叫,以在滑動時更新 <InputAccessoryView> 框架。此外,鍵盤高度的變更未被這些事件捕獲。這會產生一類像這樣的錯誤

在 iPhone X 上,文字和表情符號鍵盤的高度不同。大多數使用鍵盤事件來操縱文字輸入框架的應用程式都必須修正上述錯誤。我們的解決方案是承諾使用 .inputAccessoryView 屬性,這意味著響應者基礎架構會處理像這樣的框架更新。


我們遇到的另一個棘手的錯誤是避免 iPhone X 上的主畫面橫條。您可能會想,「Apple 開發 safeAreaLayoutGuide 就是為了這個原因,這很簡單!」。我們也同樣天真。第一個問題是原生 <InputAccessoryView> 實作在即將出現之前沒有要錨定的視窗。沒關係,我們可以覆寫 -(BOOL)becomeFirstResponder 並在那裡強制執行版面配置約束。遵守這些約束會將輔助視圖向上推,但另一個錯誤出現了:

輸入輔助視圖成功避免了主畫面橫條,但現在不安全區域後面的內容是可見的。解決方案在於這個 radar。我將原生 <InputAccessoryView> 階層結構包裝在一個不符合 safeAreaLayoutGuide 約束的容器中。原生容器涵蓋了不安全區域中的內容,而 <InputAccessoryView> 則保持在安全區域邊界內。


範例用法

以下是一個範例,它建置了一個鍵盤工具列按鈕來重設 <TextInput> 狀態。

class TextInputAccessoryViewExample extends React.Component<
{},
*,
> {
constructor(props) {
super(props);
this.state = {text: 'Placeholder Text'};
}

render() {
const inputAccessoryViewID = 'inputAccessoryView1';
return (
<View>
<TextInput
style={styles.default}
inputAccessoryViewID={inputAccessoryViewID}
onChangeText={text => this.setState({text})}
value={this.state.text}
/>
<InputAccessoryView nativeID={inputAccessoryViewID}>
<View style={{backgroundColor: 'white'}}>
<Button
onPress={() =>
this.setState({text: 'Placeholder Text'})
}
title="Reset Text"
/>
</View>
</InputAccessoryView>
</View>
);
}
}

另一個關於 黏性文字輸入的範例可以在儲存庫中找到

我何時可以使用它?

此功能實作的完整提交記錄在 這裡<InputAccessoryView> 將在即將發佈的 v0.55.0 版本中提供。

鍵盤操作愉快 :)

將 AWS 與 React Native 搭配使用

·9 分鐘閱讀
Richard Threlkeld
AWS Mobile 的資深技術產品經理

AWS 在科技產業中以雲端服務提供商而聞名。這些服務包括運算、儲存和資料庫技術,以及完全託管的無伺服器產品。AWS Mobile 團隊一直與客戶和 JavaScript 生態系統的成員密切合作,以使雲端連線的行動和 Web 應用程式更安全、可擴展且更易於開發和部署。我們從 完整的入門套件 開始,但最近又有了一些新的發展。

這篇部落格文章討論了一些對 React 和 React Native 開發人員來說有趣的事情

  • AWS Amplify,一個用於使用雲端服務的 JavaScript 應用程式的宣告式程式庫
  • AWS AppSync,一個完全託管的 GraphQL 服務,具有離線和即時功能

AWS Amplify

使用 Create React Native App 和 Expo 等工具可以非常輕鬆地引導 React Native 應用程式。但是,當您嘗試將用例與基礎架構服務相匹配時,將它們連線到雲端可能會很具挑戰性。例如,您的 React Native 應用程式可能需要上傳照片。這些照片是否應該按使用者受到保護?這可能意味著您需要某種類型的註冊或登入程序。您想要自己的使用者目錄還是要使用社群媒體提供商?也許您的應用程式還需要在使用者登入後呼叫具有自訂業務邏輯的 API。

為了幫助 JavaScript 開發人員解決這些問題,我們發佈了一個名為 AWS Amplify 的程式庫。該設計被分解為任務的「類別」,而不是 AWS 特定的實作。例如,如果您希望使用者註冊、登入,然後上傳私人照片,您只需將 AuthStorage 類別拉入您的應用程式即可

import { Auth } from 'aws-amplify';

Auth.signIn(username, password)
.then(user => console.log(user))
.catch(err => console.log(err));

Auth.confirmSignIn(user, code)
.then(data => console.log(data))
.catch(err => console.log(err));

在上面的程式碼中,您可以看到 Amplify 協助您完成的一些常見任務的範例,例如將多重因素驗證 (MFA) 程式碼與電子郵件或簡訊搭配使用。目前支援的類別有

  • Auth:提供憑證自動化。開箱即用的實作使用 AWS 憑證進行簽署,以及來自 Amazon Cognito 的 OIDC JWT 權杖。支援常見的功能,例如 MFA 功能。
  • Analytics:只需一行程式碼,即可在 Amazon Pinpoint 中取得已驗證或未驗證使用者的追蹤。您可以根據自己的喜好擴展此功能以取得自訂指標或屬性。
  • API:提供以安全方式與 RESTful API 互動,利用 AWS Signature Version 4。API 模組非常適合具有 Amazon API Gateway 的無伺服器基礎架構。
  • Storage:簡化的命令,用於在 Amazon S3 中上傳、下載和列出內容。您也可以輕鬆地將資料按使用者分組為公開或私人內容。
  • Caching:跨 Web 應用程式和 React Native 的 LRU 快取介面,使用特定於實作的持久性。
  • i18n 和 Logging:提供國際化和本地化功能,以及偵錯和記錄功能。

Amplify 的優點之一是它在設計中編碼了針對您的特定程式設計環境的「最佳實務」。例如,我們與客戶和 React Native 開發人員合作發現,在開發期間為使事情快速運作而採取的捷徑會通過生產堆疊。這些可能會損害可擴展性或安全性,並強制基礎架構重新架構和程式碼重構。

我們如何幫助開發人員避免這種情況的一個範例是 具有 AWS Lambda 的無伺服器參考架構。這些架構向您展示了在建置後端時,一起使用 Amazon API Gateway 和 AWS Lambda 的最佳實務。此模式編碼到 Amplify 的 API 類別中。您可以使用此模式與多個不同的 REST 端點互動,並將標頭一直傳遞到您的 Lambda 函式以取得自訂業務邏輯。我們也發佈了 AWS Mobile CLI,用於使用這些功能引導新的或現有的 React Native 專案。若要開始使用,只需透過 npm 安裝,然後依照設定提示操作

npm install --global awsmobile-cli
awsmobile configure

特定於行動生態系統的編碼最佳實務的另一個範例是密碼安全性。預設的 Auth 類別實作利用 Amazon Cognito 使用者集區進行使用者註冊和登入。此服務實作 安全遠端密碼協定,作為在驗證嘗試期間保護使用者的一種方式。如果您傾向於閱讀 協定的數學原理,您會注意到,在基本根上計算密碼驗證器以產生群組時,您必須使用大的質數。在 React Native 環境中,JIT 已停用。這使得用於安全操作 (如這個操作) 的 BigInteger 計算效能較差。為了考慮到這一點,我們在 Android 和 iOS 中發佈了原生橋接器,您可以將其連結到您的專案中

npm install --save aws-amplify-react-native
react-native link amazon-cognito-identity-js

我們也很高興看到 Expo 團隊已將其包含在 他們的最新 SDK 中,以便您可以在不退出的情況下使用 Amplify。

最後,針對 React Native (和 React) 開發,Amplify 包含 高階組件 (HOC),用於輕鬆封裝功能,例如用於註冊和登入您的應用程式

import Amplify, { withAuthenticator } from 'aws-amplify-react-native';
import aws_exports from './aws-exports';

Amplify.configure(aws_exports);

class App extends React.Component {
...
}

export default withAuthenticator(App);

底層組件也以 <Authenticator /> 的形式提供,這讓您可以完全控制自訂 UI。它還為您提供了一些關於管理使用者狀態的屬性,例如他們是否已登入或正在等待 MFA 確認,以及您可以在狀態變更時觸發的回呼。

同樣地,您會找到通用的 React 組件,您可以將其用於不同的用例。您可以根據自己的需求自訂這些組件,例如,在 Storage 模組中顯示來自 Amazon S3 的所有私人圖片

<S3Album
level="private"
path={path}
filter={(item) => /jpg/i.test(item.path)}/>

您可以透過 props 控制許多組件功能,如先前所示,使用公開或私人儲存選項。甚至還有在使用者與某些 UI 組件互動時自動收集分析的功能

return <S3Album track/>

AWS Amplify 偏好慣例優於組態的開發風格,並在全域初始化常式或類別層級進行初始化。最快速的入門方式是使用 aws-exports 檔案。然而,開發人員也可以獨立使用此程式庫與現有資源。

如需深入瞭解其理念並觀看完整示範,請查看 AWS re:Invent 的影片。

AWS AppSync

在 AWS Amplify 發布後不久,我們也發布了 AWS AppSync。這是一項完全受管的 GraphQL 服務,同時具備離線和即時功能。雖然您可以使用不同用戶端程式設計語言 (包括原生 Android 和 iOS) 中的 GraphQL,但它在 React Native 開發人員中非常受歡迎。這是因為其資料模型非常適合單向資料流和元件階層。

AWS AppSync 讓您能夠連線至您 AWS 帳戶中的資源,表示您擁有並控制您的資料。這透過使用資料來源來完成,而此服務支援 Amazon DynamoDBAmazon ElasticsearchAWS Lambda。這讓您能夠在單一 GraphQL API 中,以結構描述形式結合功能 (例如 NoSQL 和全文檢索)。這讓您可以混合和搭配資料來源。AppSync 服務也可以從結構描述佈建,因此如果您不熟悉 AWS 服務,您可以編寫 GraphQL SDL,按一下按鈕,即可自動啟動並執行。

AWS AppSync 中的即時功能透過GraphQL 訂閱和廣為人知的事件型模式來控制。由於 AWS AppSync 中的訂閱是在結構描述上透過 GraphQL 指令來控制,且結構描述可以使用任何資料來源,這表示您可以從資料庫操作 (使用 Amazon DynamoDB 和 Amazon Elasticsearch Service) 或從基礎設施的其他部分 (使用 AWS Lambda) 觸發通知。

在某種程度上與 AWS Amplify 類似,您可以在 AWS AppSync 上對您的 GraphQL API 使用企業級安全性功能。此服務可讓您快速開始使用 API 金鑰。然而,當您轉為生產環境時,它可以轉換為使用 AWS Identity and Access Management (IAM) 或來自 Amazon Cognito 使用者集區的 OIDC 權杖。您可以使用類型上的政策,在解析器層級控制存取權。您甚至可以在執行階段使用邏輯檢查進行精細的存取控制檢查,例如偵測使用者是否為特定資料庫資源的擁有者。此外,還有關於檢查群組成員資格以執行解析器或個別資料庫記錄存取的功能。

為了協助 React Native 開發人員進一步瞭解這些技術,AWS AppSync 主控台首頁上有一個您可以啟動的內建 GraphQL 範例結構描述。此範例會部署 GraphQL 結構描述、佈建資料庫表格,並自動為您連線查詢、變動和訂閱。此外,還有一個可運作的 AWS AppSync 的 React Native 範例,它利用此內建結構描述 (以及 React 範例),讓您能夠在幾分鐘內讓您的用戶端和雲端組件都執行起來。

當您使用 AWSAppSyncClient 時,入門非常簡單,它會插入 Apollo ClientAWSAppSyncClient 處理 GraphQL API 的安全性與簽署、離線功能,以及訂閱交握與協商程序

import AWSAppSyncClient from "aws-appsync";
import { Rehydrated } from 'aws-appsync-react';
import { AUTH_TYPE } from "aws-appsync/lib/link/auth-link";

const client = new AWSAppSyncClient({
url: awsconfig.graphqlEndpoint,
region: awsconfig.region,
auth: {type: AUTH_TYPE.API_KEY, apiKey: awsconfig.apiKey}
});

AppSync 主控台提供一個可供下載的組態檔,其中包含您的 GraphQL 端點、AWS 區域和 API 金鑰。然後,您可以搭配 React Apollo 使用用戶端

const WithProvider = () => (
<ApolloProvider client={client}>
<Rehydrated>
<App />
</Rehydrated>
</ApolloProvider>
);

此時,您可以使用標準 GraphQL 查詢

query ListEvents {
listEvents{
items{
__typename
id
name
where
when
description
comments{
__typename
items{
__typename
eventId
commentId
content
createdAt
}
nextToken
}
}
}
}

以上範例顯示使用 AppSync 佈建的範例應用程式結構描述進行查詢。它不僅展示與 DynamoDB 的互動,還包括資料分頁 (包括加密權杖) 以及 EventsComments 之間的類型關係。由於應用程式已使用 AWSAppSyncClient 進行設定,因此資料會自動離線保存,並在裝置重新連線時同步。

您可以在此影片中深入瞭解此技術背後的用戶端技術以及 React Native 示範。

意見回饋

這些程式庫和服務背後的團隊很想知道這些程式庫和服務對您的運作情形。他們也想知道我們還可以做些什麼,讓您更輕鬆地使用雲端服務進行 React 和 React Native 開發。如需 AWS AmplifyAWS AppSync,請在 GitHub 上聯絡 AWS Mobile 團隊。

在 React Native 中實作 Twitter 的應用程式載入動畫

·11 分鐘閱讀時間
Eli White
Eli White
Meta 軟體工程師

我非常喜歡 Twitter iOS 應用程式的載入動畫。

應用程式準備就緒後,Twitter 標誌會愉快地展開,顯示應用程式。

我想弄清楚如何使用 React Native 重新建立此載入動畫。


為了瞭解如何建置它,我首先必須瞭解載入動畫的不同部分。看到細微之處的最簡單方法是放慢速度。

其中有幾個主要部分,我們需要弄清楚如何建置。

  1. 縮放小鳥。
  2. 隨著小鳥長大,顯示底下的應用程式
  3. 在結尾稍微縮小應用程式

我花了一段時間才弄清楚如何製作這個動畫。

我最初錯誤地假設藍色背景和 Twitter 小鳥是應用程式上方的圖層,並且隨著小鳥長大,它會變得透明,從而顯示底下的應用程式。這種方法行不通,因為 Twitter 小鳥變得透明會顯示藍色圖層,而不是底下的應用程式!

親愛的讀者,您很幸運,不必經歷我經歷過的挫敗感。您可以直接跳到重點,獲得這篇不錯的教學課程!


正確的方法

在我們開始編碼之前,重要的是要瞭解如何分解它。為了幫助視覺化此效果,我在 CodePen (嵌入在幾個段落中) 中重新建立了它,因此您可以互動式地查看不同的圖層。

此效果有三個主要圖層。第一個是藍色背景圖層。即使它看起來似乎在應用程式的上方,但實際上是在後面。

然後我們有一個純白色圖層。最後,在最前面的是我們的應用程式。


此動畫的主要技巧是使用 Twitter 標誌作為 mask,並遮罩應用程式和白色圖層。我不會深入探討遮罩的細節,網路上有很多關於遮罩的資源資源 資源

在此情境中,遮罩的基本原理是讓遮罩的不透明像素顯示它們所遮罩的內容,而遮罩的透明像素則隱藏它們所遮罩的內容。

我們使用 Twitter 標誌作為遮罩,並讓它遮罩兩個圖層;純白色圖層和應用程式圖層。

為了顯示應用程式,我們將遮罩向上縮放,直到它大於整個螢幕。

在遮罩向上縮放時,我們淡入應用程式圖層的不透明度,顯示應用程式並隱藏其後面的純白色圖層。為了完成效果,我們將應用程式圖層的初始縮放比例設定為 > 1,並在動畫結束時將其縮放回 1。然後,我們隱藏非應用程式圖層,因為它們永遠不會再被看到。

俗話說,一張圖片勝過千言萬語。互動式視覺化又值多少字呢?按一下「下一步」按鈕,逐步瀏覽動畫。顯示圖層會提供您側視圖視角。網格有助於視覺化透明圖層。

現在,開始使用 React Native

好的。現在我們知道我們要建置什麼以及動畫如何運作,我們可以開始研究程式碼了 — 這才是您真正來此的目的。

此謎題的主要部分是 MaskedViewIOS,一個核心 React Native 元件。

import {MaskedViewIOS} from 'react-native';

<MaskedViewIOS maskElement={<Text>Basic Mask</Text>}>
<View style={{backgroundColor: 'blue'}} />
</MaskedViewIOS>;

MaskedViewIOS 接受 props maskElementchildren。children 會被 maskElement 遮罩。請注意,遮罩不需要是影像,它可以是任何任意檢視。上述範例的行為是呈現藍色檢視,但僅在 maskElement 中「Basic Mask」文字所在的位置可見。我們只是製作了複雜的藍色文字。

我們想要做的是呈現我們的藍色圖層,然後在其上方呈現使用 Twitter 標誌遮罩的應用程式和白色圖層。

{
fullScreenBlueLayer;
}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Image source={twitterLogo} />
</View>
}>
{fullScreenWhiteLayer}
<View style={{flex: 1}}>
<MyApp />
</View>
</MaskedViewIOS>;

這將為我們提供以下看到的圖層。

現在開始 Animated 部分

我們擁有讓此動畫運作所需的所有組件,下一步是為它們製作動畫。為了讓這個動畫感覺良好,我們將使用 React Native 的 Animated API。

Animated 讓我們先行在 JavaScript 中定義動畫。預設情況下,這些動畫在 JavaScript 中執行,並告知原生圖層在每個影格上要進行哪些變更。即使 JavaScript 會嘗試在每個影格更新動畫,它也可能無法以足夠快的速度執行,並會導致影格遺失 (不流暢)。這不是我們想要的!

Animated 具有特殊行為,可讓您在沒有這種不流暢的情況下獲得動畫。Animated 有一個名為 useNativeDriver 的旗標,它會在動畫開始時將您的動畫定義從 JavaScript 傳送到原生端,讓原生端能夠處理動畫的更新,而無需在每個影格都來回 JavaScript。useNativeDriver 的缺點是您只能更新一組特定的屬性,主要是 transformopacity。您無法使用 useNativeDriver 為背景顏色等項目製作動畫,至少目前還不行 — 我們會隨著時間推移新增更多,當然,您隨時可以為您的專案所需的屬性提交 PR,造福整個社群 😀。

由於我們希望這個動畫流暢,因此我們將在這些限制內工作。如需深入瞭解 useNativeDriver 在底層如何運作,請查看我們宣布它的部落格文章

分解我們的動畫

我們的動畫有 4 個組件

  1. 放大鳥,顯示應用程式和純白色圖層
  2. 淡入應用程式
  3. 縮小應用程式
  4. 完成時隱藏白色圖層和藍色圖層

使用 Animated 時,有兩種主要方法可以定義動畫。第一種是使用 Animated.timing,它可讓您精確地說出動畫將執行的時間長度,以及平滑運動的緩和曲線。另一種方法是使用基於物理的 API,例如 Animated.spring。使用 Animated.spring,您可以指定彈簧中的摩擦力和張力等參數,並讓物理定律運行您的動畫。

我們有多個想要同時運行的動畫,這些動畫彼此密切相關。例如,我們希望應用程式在遮罩處於中間顯示階段時開始淡入。由於這些動畫密切相關,我們將使用 Animated.timing 和單一 Animated.Value

Animated.Value 是原生值的包裝函式,Animated 使用它來了解動畫的狀態。對於完整的動畫,您通常只想要一個此類值。大多數使用 Animated 的組件都會將值儲存在狀態中。

由於我將此動畫視為在完整動畫的不同時間點發生的步驟,因此我們將從 0 開始我們的 Animated.Value,表示完成度為 0%,並在 100 結束我們的值,表示完成度為 100%。

我們元件的初始狀態將如下所示。

state = {
loadingProgress: new Animated.Value(0),
};

當我們準備好開始動畫時,我們告訴 Animated 將此值動畫化為 100。

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true, // This is important!
}).start();

然後,我嘗試粗略估計動畫的不同部分以及我希望它們在整體動畫的不同階段具有的值。以下是動畫的不同部分以及我認為它們在時間進程中不同點的值的表格。

Twitter 小鳥遮罩應從縮放比例 1 開始,並且在向上放大之前會變小。因此,在動畫進行到 10% 時,它的縮放比例值應為 0.8,然後在結尾處向上放大到縮放比例 70。老實說,選擇 70 非常隨意,它需要夠大才能讓小鳥完全顯示螢幕,而 60 不夠大 😀。但關於這部分有趣的是,數字越高,它看起來成長的速度就越快,因為它必須在相同的時間量內到達那裡。這個數字經過一些試驗和錯誤,才與此標誌看起來良好。不同大小的標誌/裝置將需要不同的結束縮放比例,以確保整個螢幕都被顯示出來。

應用程式應保持不透明一段時間,至少要持續到 Twitter 標誌變小。根據官方動畫,我希望在小鳥處於中間放大階段時開始顯示它,並在相當快地完全顯示它。因此,在 15% 時我們開始顯示它,在整體動畫進行到 30% 時,它完全可見。

應用程式縮放比例從 1.1 開始,並在動畫結束時縮小到其正常縮放比例。

現在,開始編碼。

我們在上面基本上做的是將動畫進度百分比的值對應到個別部分的值。我們使用 Animated 和 .interpolate 來做到這一點。我們使用基於 this.state.loadingProgress 的內插值,為動畫的每個部分建立 3 個不同的樣式物件。

const loadingProgress = this.state.loadingProgress;

const opacityClearToVisible = {
opacity: loadingProgress.interpolate({
inputRange: [0, 15, 30],
outputRange: [0, 0, 1],
extrapolate: 'clamp',
// clamp means when the input is 30-100, output should stay at 1
}),
};

const imageScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 10, 100],
outputRange: [1, 0.8, 70],
}),
},
],
};

const appScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 100],
outputRange: [1.1, 1],
}),
},
],
};

現在我們有了這些樣式物件,我們可以在呈現稍早文章中的檢視程式碼片段時使用它們。請注意,只有 Animated.ViewAnimated.TextAnimated.Image 能夠使用使用 Animated.Value 的樣式物件。

const fullScreenBlueLayer = (
<View style={styles.fullScreenBlueLayer} />
);
const fullScreenWhiteLayer = (
<View style={styles.fullScreenWhiteLayer} />
);

return (
<View style={styles.fullScreen}>
{fullScreenBlueLayer}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Animated.Image
style={[styles.maskImageStyle, imageScale]}
source={twitterLogo}
/>
</View>
}>
{fullScreenWhiteLayer}
<Animated.View
style={[opacityClearToVisible, appScale, {flex: 1}]}>
{this.props.children}
</Animated.View>
</MaskedViewIOS>
</View>
);

太棒了!我們現在讓動畫部分看起來符合我們的期望。現在我們只需要清理藍色和白色圖層,它們永遠不會再被看到。

為了知道何時可以清理它們,我們需要知道動畫何時完成。幸運的是,在我們呼叫 Animated.timing 的地方,.start 接受一個選用的回呼,該回呼會在動畫完成時執行。

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true,
}).start(() => {
this.setState({
animationDone: true,
});
});

現在我們在 state 中有一個值來知道我們是否已完成動畫,我們可以修改我們的藍色和白色圖層以使用它。

const fullScreenBlueLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenBlueLayer]} />
);
const fullScreenWhiteLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenWhiteLayer]} />
);

瞧!我們的動畫現在可以運作了,並且我們在動畫完成後清理了未使用的圖層。我們已經建置了 Twitter 應用程式載入動畫!

但是等等,我的無法運作!

親愛的讀者,別擔心。我也討厭指南只提供您程式碼片段,而不提供您完整的原始碼。

此元件已發布到 npm,並在 GitHub 上以 react-native-mask-loader 的形式提供。若要在您的手機上試用,請在此處在 Expo 上取得

更多閱讀資料/額外加分

  1. 在您閱讀 React Native 文件後,這本 gitbook 是瞭解更多關於 Animated 的絕佳資源。
  2. 實際的 Twitter 動畫似乎在結尾加速了遮罩顯示。嘗試修改載入器以使用不同的緩和函式 (或彈簧!),以更好地符合該行為。
  3. 目前的遮罩結束縮放比例是硬式編碼的,可能無法在平板電腦上顯示整個應用程式。根據螢幕尺寸和影像尺寸計算結束縮放比例將會是一個很棒的 PR。

React Native 每月精選 #6

·4 分鐘閱讀時間
Tomislav Tenodi
Speck 創辦人

React Native 每月會議仍在持續進行!請務必查看本文底部的註記,以瞭解下次會議的資訊。

Expo

  • 恭喜 Devin AbbottHoussein Djirdeh 預先發布了「Full Stack React Native」書籍!它引導您透過建置幾個小型應用程式來學習 React Native。
  • 發布了 reason-react-native-scripts 的第一個 (實驗性) 版本,以協助人們輕鬆試用 ReasonML
  • Expo SDK 24 已發布!它使用 React Native 0.51,並包含許多新功能和改進:獨立應用程式中的捆綁影像 (無需在第一次載入時快取!)、影像操作 API (裁剪、調整大小、旋轉、翻轉)、臉部偵測 API、新的發布通道功能 (為給定通道設定作用中發布和回滾)、追蹤獨立應用程式建置的網路儀表板,以及修復 OpenGL Android 實作和 Android 多工處理器的長期錯誤,僅舉幾例。
  • 我們將從今年 1 月開始分配更多資源給 React Navigation。我們深信,僅使用 React 元件和 Animated 以及 react-native-gesture-handler 等基本元件,就能夠且值得建置 React Native 導航,而且我們對我們已規劃的一些改進感到非常興奮。如果您想為社群做出貢獻,請查看 react-native-mapsreact-native-svg,這兩者都需要一些協助!

Infinite Red

Microsoft

  • 已啟動一個 pull request,以將核心 React Native Windows 橋接器遷移到 .NET Standard,使其有效地與作業系統無關。希望許多其他 .NET Core 平台可以使用自己的執行緒模型、JavaScript 執行階段和 UIManagers (想想 JavaScriptCore、Xamarin.Mac、Linux Gtk# 和 Samsung Tizen 選項) 來擴充橋接器。

Wix

  • Detox
    • 為了讓我們能夠擴充 E2E 測試,我們希望盡可能縮短在 CI 上花費的時間,我們正在開發 Detox 的平行化支援。
    • 提交了一個 pull request,以啟用對自訂風味組建的支援,以便更好地支援 E2E 上的模擬。
  • DetoxInstruments
    • DetoxInstruments 的殺手級功能被證明是一項非常具有挑戰性的任務,在任何給定時間取得 JavaScript 回溯追蹤都需要自訂 JSCore 實作來支援 JS 執行緒暫停。在 Wix 的應用程式上內部測試分析器揭示了關於 JS 執行緒的有趣見解。
    • 該專案對於一般使用而言仍然不夠穩定,但正在積極開發中,我們希望很快宣布它。
  • React Native Navigation
    • V2 開發步調已大幅加快,到目前為止,我們只有 1 位開發人員花費 20% 的時間在這上面,我們現在有 3 位開發人員全職投入!
  • Android 效能
    • 用最新版本 (webkitGTK 專案的尖端,具有自訂 JIT 組態) 取代 RN 中捆綁的舊 JSCore,使 JS 執行緒的效能提高了 40%。下一步是編譯 64 位元版本。這項工作是基於 Android 的 JSC 組建腳本。請在此處追蹤其目前狀態 here

下次會議

關於重新調整此會議的用途以討論單一且特定主題 (例如導航、將 React Native 模組移至個別儲存庫、文件等) 進行了一些討論。透過這種方式,我們覺得我們可以為 React Native 社群做出最大的貢獻。這可能會在下次會議中舉行。歡迎推文您希望看到涵蓋的主題。

React Native 每月精選 #5

·4 分鐘閱讀時間
Tomislav Tenodi
Speck 創辦人

React Native 每月會議持續進行!讓我們看看我們的團隊在忙些什麼。

Callstack

  • 我們一直在開發 React Native CI。最重要的是,我們已從 Travis 遷移到 Circle,為 React Native 留下單一、統一的 CI 管道。
  • 我們舉辦了 Hacktoberfest - React Native 版本,我們與與會者一起嘗試提交許多 pull request 給開源專案。
  • 我們持續開發 Haul。上個月,我們提交了兩個新版本,包括 webpack 3 支援。我們計劃新增 CRNAExpo 支援,並開發更好的 HMR。我們的路線圖在 issue 追蹤器上公開。如果您想提出改進建議或提供意見回饋,請告訴我們!

Expo

  • 發布了 Expo SDK 22 (使用 React Native 0.49) 並更新了 CRNA 以適用於它。
    • 包括改進的啟動畫面 API、基本 ARKit 支援、「DeviceMotion」API、iOS11 上的 SFAuthenticationSession 支援,以及更多
  • 您的 snacks 現在可以有多個 JavaScript 檔案,您可以透過將影像和其他資產拖曳到編輯器中來上傳它們。
  • 貢獻 react-navigation 以新增對 iPhone X 的支援。
  • 將我們的注意力集中在用 Expo 建置大型應用程式時的粗糙邊緣。例如
    • 一流支援部署到多個環境:預備、生產和任意通道。通道將支援回滾和設定給定通道的作用中發布。如果您想成為早期測試人員,請透過 @expo_io 告訴我們。
    • 我們也正在努力改進我們的獨立應用程式建置基礎設施,並新增對在獨立應用程式組建中捆綁影像和其他非程式碼資產的支援,同時保持透過無線方式更新資產的能力。

Facebook

  • 更好的 RTL 支援
    • 我們正在導入許多方向感知樣式。
      • 位置
        • (左|右) → (開始|結束)
      • 邊界
        • margin(左|右) → margin(開始|結束)
      • 內距
        • padding(左|右) → padding(開始|結束)
      • 邊框
        • borderTop(左|右)Radius → borderTop(開始|結束)Radius
        • borderBottom(左|右)Radius → borderBottom(開始|結束)Radius
        • border(左|右)Width → border(開始|結束)Width
        • border(左|右)Color → border(開始|結束)Color
    • 「左」和「右」的含義在 RTL 中針對位置、邊界、內距和邊框樣式進行了交換。在幾個月內,我們將移除此行為,並使「左」始終表示「左」,「右」始終表示「右」。重大變更隱藏在旗標下。在您的 React Native 元件中使用 I18nManager.swapLeftAndRightInRTL(false) 以選擇加入它們。
  • 開發 Flow 以輸入我們的內部原生模組,並使用這些模組在 Java 中產生介面,並在 ObjC 中產生原生實作必須實作的協定。我們希望此程式碼產生器最早在明年開源。

Infinite Red

  • 用於協助 React Native 和其他專案的新 OSS 工具。更多資訊請參閱此處
  • 修改 Ignite 以進行新的樣板發布 (代號:Bowser)

Shoutem

  • 改進 Shoutem 上的開發流程。我們希望簡化從建立應用程式到第一個自訂螢幕的流程,並使其非常容易,從而降低新 React Native 開發人員的門檻。準備了一些工作坊來測試新功能。我們也改進了 Shoutem CLI 以支援新流程。
  • Shoutem UI 收到了一些元件改進和錯誤修復。我們也檢查了與最新 React Native 版本的相容性。
  • Shoutem 平台收到了一些值得注意的更新,新的整合作為 開源擴充功能專案 的一部分提供。我們非常高興看到其他開發人員在 Shoutem 擴充功能上進行積極開發。我們積極聯絡並提供關於其擴充功能的建議和指導。

下次會議

下次會議定於 2017 年 12 月 6 日星期三舉行。如果您對我們應如何改進會議的輸出有任何建議,請在 Twitter 上 ping 我。

React Native 每月精選 #4

·3 分鐘閱讀時間
Mike Grabowski
Mike Grabowski
Callstack 技術長兼共同創辦人

React Native 每月會議持續進行!以下是每個團隊的筆記

Callstack

  • React Native EU 已經結束。來自 33 個國家/地區的 300 多名參與者造訪了弗羅茨瓦夫。演講可以在 YouTube 上找到。
  • 在會議之後,我們正慢慢回到我們的開源排程。值得一提的是,我們正在開發 react-native-opentok 的下一個版本,該版本修復了大多數現有問題。

GeekyAnts

嘗試透過以下方式降低開發人員採用 React Native 的門檻

  • React Native EU 上宣布 BuilderX.io。BuilderX 是一種設計工具,可直接與 JavaScript 檔案 (目前僅支援 React Native) 搭配使用,以產生美觀、可讀且可編輯的程式碼。
  • 推出了 ReactNativeSeed.com,它為您的下一個 React Native 專案提供了一組樣板。它提供了多種選項,包括用於資料類型的 TypeScript 和 Flow、用於狀態管理的 MobX、Redux 和 mobx-state-tree,以及作為堆疊的 CRNA 和純 React-Native。

Expo

  • 將很快發布 SDK 21,其中新增了對 react-native 0.48.3 的支援,以及 Expo SDK 中的一堆錯誤修復/可靠性改進/新功能,包括影片錄製、新的啟動畫面 API、對 react-native-gesture-handler 的支援,以及改進的錯誤處理。
  • 回覆:react-native-gesture-handlerKrzysztof MagieraSoftware Mansion 成員)持續推進此專案,而我們一直在協助他進行測試並資助他一部分的開發時間。將此功能整合到 SDK21 的 Expo 中,將讓大家可以在 Snack 中輕鬆試用,因此我們很期待看到大家會創造出什麼。
  • 回覆:改善錯誤日誌記錄/處理 - 請參閱這個內部 Expo PR 的 gist,以了解有關日誌記錄的詳細資訊(特別是「問題 2」),以及這個 commit,了解處理匯入 npm 標準函式庫模組失敗嘗試的變更。在 React Native 中,上游有許多機會可以改善錯誤訊息,我們將致力於後續的上游 PR。社群的參與將會非常棒。
  • native.directory 持續成長,您可以從GitHub repo 新增您的專案。
  • 參訪北美各地的黑客松,包括 PennAppsHack The NorthHackMIT,以及即將到來的 MHacks

Facebook

  • 致力於改善 Android 上的 <Text><TextInput> 元件。(<TextInput> 的原生自動成長;深度巢狀 <Text> 元件佈局問題;更好的程式碼結構;效能最佳化)。
  • 我們仍在尋找更多貢獻者,協助分類 issue 和 pull request。

Microsoft

  • 為 CodePush 發布程式碼簽署功能。React Native 開發人員現在能夠在 CodePush 中簽署他們的應用程式 bundle。公告可以在這裡找到。
  • 致力於完成 CodePush 與 Mobile Center 的整合。同時也在考慮測試/crash 整合。

下次會議

下一次會議預定在 2017 年 10 月 10 日星期三舉行。由於這只是我們的第四次會議,我們想知道這些筆記對 React Native 社群有什麼幫助。如果您對我們應該如何改進會議的產出有任何建議,請隨時在 Twitter 上 ping 我。

React Native 每月精選 #3

·5 分鐘閱讀
Mike Grabowski
Mike Grabowski
Callstack 技術長兼共同創辦人

React Native 每月會議持續進行!本月的會議時間較短,因為我們的大部分團隊都忙於交付。下個月,我們將在波蘭弗羅茨瓦夫舉行的 React Native EU 會議上。請務必購票,並在那裡與您見面!同時,讓我們看看我們的團隊在忙些什麼。

團隊

在第三次會議中,有 5 個團隊加入我們

筆記

以下是每個團隊的筆記

Callstack

  • 最近開源了 react-native-material-palette。它可以從圖片中提取顯著的色彩,以協助您創建視覺上引人入勝的應用程式。目前僅限 Android,但我們正在研究未來增加對 iOS 的支援。
  • 我們已將 HMR 支援加入 haul 以及許多其他酷炫的東西!請查看最新的版本。
  • React Native EU 2017 即將到來!下個月將是 React Native 和波蘭的月份!請務必在這裡搶購最後的門票 here

Expo

  • 發布了在 Snack 上安裝 npm 套件的支援。通常的 Expo 限制適用 - 套件不能依賴 Expo 中尚未包含的自訂原生 API。我們也在努力支援 Snack 中的多個檔案和上傳資源。Satyajit 將在 React Native Europe 上談論 Snack。
  • 發布了 SDK20,其中包含相機、支付、安全儲存、磁力計、暫停/恢復 fs 下載以及改進的啟動/載入畫面。
  • 持續與 Krzysztof 合作開發 react-native-gesture-handler。請試用看看,重建一些您先前使用 PanResponder 或原生手勢辨識器建立的手勢,並告訴我們您遇到的問題。
  • 實驗 JSC 偵錯協定,並處理 Canny 上的一系列功能請求。

Facebook

  • 上個月我們討論了 GitHub issue tracker 的管理,並且我們將嘗試進行改進以解決專案的可維護性問題。
  • 目前,未解決 issue 的數量穩定在 600 個左右,而且似乎可能會在一段時間內保持這種狀態。在過去一個月中,由於缺乏活動(定義為過去 60 天內沒有評論),我們關閉了 690 個 issue。在這些 690 個 issue 中,有 58 個因各種原因重新開啟(維護者承諾提供修復,或貢獻者為保持 issue 開啟提出了很好的理由)。
  • 我們計劃在可預見的未來繼續自動關閉過時的 issue。我們希望達到一種狀態,即追蹤器中開啟的每個有影響力的 issue 都能得到處理,但我們尚未達到這個目標。我們需要維護者的全力協助來分類 issue,並確保我們不會錯過引入回歸或引入重大變更的 issue,特別是那些影響新建立專案的 issue。有興趣提供協助的人可以使用 Facebook GitHub Bot 來分類 issue 和 pull request。新的維護者指南包含有關分類和使用 GitHub Bot 的更多資訊。請將自己新增到 issue 工作小組,並鼓勵其他活躍的社群成員也這樣做!

Microsoft

  • 新的 Skype 應用程式建立在 React Native 之上,以便盡可能在平台之間共享更多程式碼。基於 React Native 的 Skype 應用程式目前已在 Android 和 iOS 應用程式商店中提供。
  • 在基於 React Native 構建 Skype 應用程式時,我們會向 React Native 發送 pull request,以解決我們遇到的錯誤和缺少的功能。到目前為止,我們已經合併了大約 70 個 pull request
  • React Native 使我們能夠從相同的程式碼庫為 Android 和 iOS Skype 應用程式提供支援。我們也希望使用該程式碼庫為 Skype 網路應用程式提供支援。為了幫助我們實現這個目標,我們在 React/React Native 之上建立並開源了一個薄層,稱為 ReactXP。ReactXP 提供了一組跨平台元件,當以 iOS/Android 為目標時,這些元件會映射到 React Native,而當以網路為目標時,則會映射到 react-dom。ReactXP 的目標與另一個名為 React Native for Web 的開源函式庫類似。ReactXP FAQ 中簡要描述了這些函式庫的方法有何不同。

Shoutem

  • 我們正在繼續努力改善和簡化使用 Shoutem 建構應用程式時的開發人員體驗。
  • 開始將我們所有的應用程式遷移到 react-navigation,但我們將此延後到發布更穩定的版本,或其中一個原生導航解決方案變得穩定為止。
  • 將我們所有的 擴充功能 和我們大多數的開源函式庫(animationthemeui)更新到 React Native 0.47.1。

下次會議

下一次會議預定在 2017 年 9 月 13 日星期三舉行。由於這只是我們的第三次會議,我們想知道這些筆記對 React Native 社群有什麼幫助。如果您對我們應該如何改進會議的產出有任何建議,請隨時在 Twitter 上 ping 我。

React Native 在 Marketplace 的效能表現

·5 分鐘閱讀
Facebook 的軟體工程師

React Native 在 Facebook 系列的多個應用程式的多個位置中使用,包括主要 Facebook 應用程式中的頂層標籤。我們這篇文章的重點是一個高度可見的產品,Marketplace。它在大約十幾個國家/地區提供,並允許用戶發現其他用戶提供的產品和服務。

在 2017 年上半年,透過 Relay 團隊、Marketplace 團隊、Mobile JS Platform 團隊和 React Native 團隊的共同努力,我們將 Android Year Class 2010-11 裝置 的 Marketplace 互動時間 (TTI) 縮短了一半。Facebook 歷來將這些裝置視為低階 Android 裝置,它們在任何平台或裝置類型上的 TTI 都是最慢的。

典型的 React Native 啟動看起來像這樣

免責聲明:比例不具代表性,並且會根據 React Native 的配置和使用方式而有所不同。

我們首先初始化 React Native 核心(又名「Bridge」),然後運行產品特定的 JavaScript,這決定了 React Native 將在原生處理時間中渲染哪些原生視圖。

不同的方法

我們早期的錯誤之一是讓 Systrace 和 CTScan 驅動我們的效能工作。這些工具幫助我們在 2016 年找到了許多唾手可得的成果,但我們發現 Systrace 和 CTScan 都不能代表生產情境,並且無法模擬在真實環境中發生的情況。時間分配的比例通常不正確,有時甚至大相逕庭。在極端情況下,我們預期需要幾毫秒才能完成的事情實際上需要數百甚至數千毫秒。儘管如此,CTScan 仍然很有用,我們發現它在迴歸影響生產之前捕獲了三分之一的迴歸。

在 Android 上,我們將這些工具的缺點歸因於以下事實:1) React Native 是一個多執行緒框架,2) Marketplace 與大量複雜的視圖(例如 Newsfeed 和其他頂層標籤)共存,以及 3) 計算時間差異很大。因此,這半年,我們讓生產測量和分配驅動了我們幾乎所有的決策和優先順序。

生產儀器化的途徑

從表面上看,儀器化生產可能聽起來很簡單,但事實證明這是一個相當複雜的過程。它花費了多個 2-3 週的迭代週期;由於將 commit 登陸到 master、將應用程式推送到 Play 商店以及收集足夠的生產樣本以對我們的工作有信心都存在延遲。每個迭代週期都涉及發現我們的分配是否準確、它們是否具有正確的粒度級別,以及它們是否正確地加總到整個時間跨度。我們不能依賴 alpha 和 beta 版本,因為它們不能代表一般人群。從本質上講,我們非常繁瑣地基於數百萬個樣本的總和構建了一個非常準確的生產追蹤。

我們仔細驗證分配中的每一毫秒是否正確地加總到其父度量的一個原因是,我們很早就意識到我們的儀器化存在差距。事實證明,我們最初的分配沒有考慮到執行緒跳躍引起的停頓。執行緒跳躍本身並不昂貴,但跳躍到已經在工作的繁忙執行緒非常昂貴。我們最終透過在正確的時刻散佈 Thread.sleep() 呼叫在本地重現了這些阻塞,並且我們透過以下方式設法修復了它們

  1. 移除我們對 AsyncTask 的依賴,
  2. 撤銷在 UI 執行緒上強制初始化 ReactContext 和 NativeModules,以及
  3. 移除在初始化時測量 ReactRootView 的依賴。

總之,移除這些執行緒阻塞問題將啟動時間縮短了 25% 以上。

生產指標也挑戰了我們之前的一些假設。例如,我們過去常常在啟動路徑上預先載入許多 JavaScript 模組,假設將模組共置在一個 bundle 中會降低它們的初始化成本。但是,預先載入和共置這些模組的成本遠遠超過了收益。透過重新配置我們的 inline require 黑名單並從啟動路徑中移除 JavaScript 模組,我們能夠避免載入不必要的模組,例如 Relay Classic(當僅 Relay Modern 是必要的時候)。今天,我們的 RUN_JS_BUNDLE 分配速度提高了 75% 以上。

我們也透過調查特定於產品的原生模組找到了優勢。例如,透過延遲注入原生模組的依賴項,我們將該原生模組的成本降低了 98%。透過消除 Marketplace 啟動與其他產品的競爭,我們將啟動時間縮短了相當的間隔。

最好的是,這些改進中的許多都廣泛適用於使用 React Native 建構的所有螢幕。

結論

人們認為 React Native 啟動效能問題是由於 JavaScript 速度慢或網路時間過高引起的。雖然加速 JavaScript 等事物會將 TTI 降低相當可觀的總和,但與之前認為的相比,這些因素對 TTI 的貢獻百分比較小。

到目前為止的教訓是測量、測量、再測量! 一些優勢來自將運行時成本轉移到構建時間,例如 Relay Modern 和 Lazy NativeModules。其他優勢來自於透過更聰明地並行化程式碼或移除無效程式碼來避免工作。還有一些優勢來自於 React Native 的大型架構變更,例如清理執行緒阻塞。效能沒有萬能的解決方案,而長期的效能提升將來自於增量儀器化和改進。不要讓認知偏見影響您的決策。相反,請仔細收集和解釋生產數據,以指導未來的工作。

未來計劃

從長遠來看,我們希望 Marketplace TTI 與使用原生建構的類似產品相當,並且總體而言,React Native 效能與原生效能相當。此外,儘管這半年我們大幅降低了約 80% 的 bridge 啟動成本,但我們計劃透過 Prepack 和更多的構建時間處理等專案,將 React Native bridge 的成本降至接近於零。

React Native 每月精選 #2

·8 分鐘閱讀
Tomislav Tenodi
Shoutem 產品經理

React Native 每月會議持續進行!在本次會議中,Infinite RedChain React, the React Native Conference 背後的大腦)加入了我們。由於這裡的大多數人都在 Chain React 上發表演講,我們將會議推遲了一週。會議的演講已發布在網路上,我鼓勵您查看一下。那麼,讓我們看看我們的團隊在忙些什麼。

團隊

在第二次會議中,有 9 個團隊加入我們

筆記

以下是每個團隊的筆記

Airbnb

Callstack

  • Mike Grabowski 一如既往地管理 React Native 的每月發布,包括發布了一些 beta 版本。特別是,致力於發布 v0.43.5 build 到 npm,因為它可以解除 Windows 用戶的封鎖!
  • 關於 Haul 的工作正在緩慢但持續地進行中。有一個 pull request 添加了 HMR,並且其他改進也已發布。最近讓一些行業領導者採用了它。可能計劃開始在該領域進行全職有償工作。
  • 來自 Jest 團隊的 Michał Pierzchała 本月加入了 Callstack。他將協助維護 Haul,並可能參與 Metro BundlerJest 的工作。
  • Satyajit Sahoo 現在和我們在一起了,太棒了!
  • 我們的 OSS 部門即將推出許多很酷的東西。特別是,致力於將 Material Palette API 引入 React Native。計劃最終發布我們的原生 iOS 套件,該套件旨在提供與原生組件 1:1 的外觀和風格。

Expo

  • 最近推出了 Native Directory,以幫助發現和評估 React Native 生態系統中的函式庫。問題:函式庫太多,難以測試,需要手動應用啟發式方法,並且不清楚哪些是您應該使用的最佳函式庫。也很難知道某個東西是否與 CRNA/Expo 相容。因此,Native Directory 試圖解決這些問題。查看一下並將您的函式庫 新增到其中。函式庫列表在這裡 here。這只是我們的第一次嘗試,我們希望它由社群擁有和運行,而不僅僅是 Expo 的人員。因此,如果您認為這很有價值並希望使其變得更好,請盡一份心力!
  • Snack 中使用 Expo SDK 19 添加了對安裝 npm 套件的初始支援。如果您遇到任何問題,請告訴我們,我們仍在解決一些錯誤。連同 Native Directory,這應該可以輕鬆測試僅具有 JS 依賴項或 Expo SDK 中包含的依賴項的函式庫。試試看
  • 發布了 Expo SDK19,其中包含各方面的許多改進,而且我們現在正在使用 更新的 Android JSC
  • 正在與 Alexander Kotliarskyi 合作在文件中編寫指南,其中列出了有關如何改善應用程式使用者體驗的提示。請加入並添加到列表中或協助撰寫部分內容!
  • 繼續致力於:音訊/視訊、相機、手勢(與 Software Mansion 合作,react-native-gesture-handler)、GL 相機整合,並希望在 SDK20 (8 月) 中首次實現其中一些功能,並在此之前對其他功能進行重大改進。我們才剛開始在 Expo 客戶端中構建後台工作基礎架構(地理位置、音訊、處理通知等)。
  • Adam Miskiewicz 在模仿 react-navigationUINavigationController 的轉換方面取得了一些不錯的進展。查看他在 他的推文 中發布的早期版本 - 即將發布。另請查看他 上游MaskedViewIOS。如果您有技能和意願為 Android 實作 MaskedView,那將會非常棒!

Facebook

  • Facebook 正在內部探索能夠將原生 ComponentKitLitho 組件嵌入到 React Native 內部。
  • 非常歡迎對 React Native 做出貢獻!如果您想知道如何貢獻,「如何貢獻」指南 描述了我們的開發流程,並列出了發送您的第一個 pull request 的步驟。還有其他不需要編寫程式碼的貢獻方式,例如分類 issue 或更新文件。
    • 在撰寫本文時,React Native 有 635未解決 issue249未解決 pull request。這對於我們的維護者來說是壓倒性的,並且當內部修復問題時,很難確保相關任務已更新。
    • 我們不確定在保持社群滿意的同時,處理這個問題的最佳方法是什麼。一些(但並非全部!)選項包括關閉過時的 issue、給予更多人管理 issue 的權限,以及自動關閉不遵循 issue 範本的 issue。我們撰寫了「維護者期望」指南,以設定期望並避免意外。如果您對如何使維護者的體驗更好,並確保開啟 issue 和 pull request 的人感到被傾聽和重視有任何想法,請告訴我們!

GeekyAnts

  • 我們在 Chain React 上演示了適用於 React Native 檔案的 Designer Tool。許多與會者註冊了候補名單。
  • 我們也在研究其他跨平台解決方案,例如 Google Flutter(即將進行重大比較)、Kotlin NativeApache Weex,以了解架構差異以及我們可以從中學習什麼來提高 React Native 的整體效能。
  • 將我們的大多數應用程式切換到 react-navigation,這提高了整體效能。
  • 此外,宣布了 NativeBase Market - 一個適用於 React Native 組件和應用程式的市場(為開發人員和由開發人員建立)。

Infinite Red

Microsoft

  • CodePush 現在已整合到 Mobile Center 中。現有用戶的工作流程不會有任何改變。
    • 有些人回報了一個關於重複應用程式的問題 - 他們已經在 Mobile Center 上有一個應用程式。我們正在努力解決這些問題,但如果您有兩個應用程式,請告訴我們,我們可以為您合併它們。
  • Mobile Center 現在支援 CodePush 的推播通知。我們也展示了通知和 CodePush 的組合如何用於 A/B 測試應用程式 - 這是 ReactNative 架構獨有的功能。
  • VS Code 在 ReactNative 上存在一個已知的偵錯問題 - 未來幾天發布的擴充功能版本將修復該問題。
  • 由於 Microsoft 內部還有許多其他團隊也在開發 React Native,我們將努力讓所有團隊在下次會議中獲得更好的代表性。

Shoutem

  • 完成了使 Shoutem 上的 React Native 開發更輕鬆的過程。您可以在 Shoutem 上開發應用程式時使用所有標準的 react-native 命令。
  • 我們做了大量工作,試圖弄清楚如何最好地處理 React Native 上的效能分析。文件 的很大一部分已過時,我們將盡力在官方文件中創建 pull request,或至少在部落格文章中撰寫我們的一些結論。
  • 將我們的導航解決方案切換到 react-navigation,因此我們可能很快就會收到一些回饋。
  • 我們在我們的工具包中發布了 一個新的 HTML 組件,它可以將原始 HTML 轉換為 React Native 組件樹。

Wix

  • 我們開始為 Metro Bundler 提交 pull request,其中包含 react-native-repackager 功能。我們更新了 react-native-repackager 以支援 RN 44(我們在生產環境中使用)。我們將其用於 detox 的模擬基礎架構。
  • 在過去的三週裡,我們一直在 detox 測試中涵蓋 Wix 應用程式。這是一個關於如何在如此規模的應用程式(超過 40 位工程師)中減少手動 QA 的驚人學習體驗。我們因此解決了 detox 的幾個問題,一個新版本剛剛發布。我很高興地報告,我們正在履行「零不穩定性政策」,並且到目前為止測試始終如一地通過。
  • Android 版 Detox 進展順利。我們得到了社群的重大幫助。我們預計在大約兩週內推出初始版本。
  • DetoxInstruments,我們的效能測試工具,變得比我們最初預期的要大一點。我們現在計劃將其轉變為一個獨立工具,該工具不會與 detox 緊密耦合。它將允許調查 iOS 應用程式的整體效能。它也將與 detox 集成,以便我們可以對效能指標運行自動化測試。

下次會議

下一次會議預定在 2017 年 8 月 16 日舉行。由於這只是我們的第二次會議,我們想知道這些筆記對 React Native 社群有什麼幫助。如果您對我們應該如何改進會議的產出有任何建議,請隨時在 Twitter 上 ping 我。