沒 2 年 React Native 開發經驗,你都遇不到這些坑

2022-01-02 魔術師卡頌
React Native 開發時,如果只是寫些簡單的頁面,基本上按著官方文檔 reactnative.dev[1] 就能寫出來,但是 React Native 的 API 有幾百個,沒有一定的開發踩坑經驗,面對一些新的需求時確實會抓不到重點。

本文總結了我個人開發 React Native 中遇到的問題和一些冷門的 API,如果有有緣人看到這篇文章並解決了實際問題,那就最好不過了。


一、內置組件

本節內容主要是是對官網 React Native Core Components[2] 內容的補充,主要是說一些讓人開發體驗不爽的地方,幫助後來人避坑。

1.View

View 組件作為最基礎的組件,撐起了 RN 頁面的半壁江山,在使用的過程中有幾個屬性比較冷門但個人認為挺有用的屬性。

hitSlop 屬性:這個屬性可以擴大 View 的觸控範圍,在一些小按鈕上用收益還是很大的pointerEvents 屬性:這個屬性類似 CSS 的 pointer-events 屬性,可以控制 View 對 touch 事件的響應2.Text

Text 組件是很常用的屬性,有幾個小點需要開發者注意一下:

Android 上存在吞字現象,現象是部分機型上最後一個字符不顯示,原因不明。目前的折衷方案是文字的最後一行多加一個空格 or 零寬字符Android 有個屬性叫 includeFontPadding,設置為 false 後可以減少文字上下的 padding(這個 padding 是為角標字符預留的,例如 H₂O、2ⁿᵈ),這樣可以更好的實現上下垂直居中對齊實現文字的居中對齊時,最好用一個 View 嵌套一個 Text 標籤,然後給 View 設置一些 flex 屬性控制 Text 居中對齊。Web 開發中經常使用 lineheight 屬性實現單行文字的垂直居中對齊,這種實現方式本來就是權宜之計,在 RN 上行不太通。最佳實踐還是利用 flex 屬性實現居中對齊字體的配置相對來說比較麻煩,有個不錯的教程 Ultimate guide to use custom fonts in react native[3] 可以參考一下3.TextInput

輸入框組件也是很常用的屬性,個人用下來有幾個不爽的地方:

iOS/Android 的默認樣式差距比較大,不做封裝的話會寫非常多的平臺相關代碼

placeholder 的文字比較長時,若出現換行現象,沒有 API 去控制它的行高

若一個頁面出現多個 TextInput 組件時,需要用 ScrollView 組件包裹,才能實現不同 TextInput 組件焦點切換的功能

4.Image

Image 組件在表現上我個人認為非常優秀了,但在一些細節上初步上手的同學可能還是不太習慣:

沒有 CSS 那麼多的濾鏡屬性,只支持模糊效果,不過個人基本沒遇到過圖像濾鏡需求加載網絡圖片時,必須指定圖片寬高,若不設置尺寸默認為 0Android 上圖片尺寸非常大時(貌似是 5000px?),圖片會直接加載不出來,不過這種場景很少很少,基本都會瓦片圖分步加載,要不然大圖會引起 OOM 的iOS/Android 對 webp 的支持也不是開箱即用的,需要分別配置:iOS 使用 SDImageWebPCoder 提供支持具體配置方案可以參考 react-native-webp-format[4]5.Modal

RN 官方之前提供的 Modal 組件有個很明顯的問題,Modal 無法覆蓋到狀態欄。比如說我們做了一個彈窗,背景是黑色半透明的,但狀態欄是白色的,這樣在感官上就非常的割裂。

所幸 0.62 版本上了一個 statusBarTranslucent 屬性,設為 true 就可以覆蓋到狀態欄之上。如果是 0.62 以下的版本,就需要改一些配置了,可以參考 stackoverflow 的這個回答:How to hide the statusBar when react-native modal shown?[5]

6.ScrollView

ScrollView 組件是 RN 提供的滑動容器組件,有幾個比較冷門但是很好用的 API 我這裡說明一下。

第一個是吸頂功能,涉及到 StickyHeaderComponent 和 stickyHeaderIndices 這兩個 API,可以實現滾動吸頂的效果,非常的好用。

第二個是 automaticallyAdjustContentInsets 屬性,有時候 iOS 滾動列表上會出現莫名其妙的空白區域,這個是 iOS Native 層實現的,RN 具體的觸發時機我沒有做詳細的測試,但基本上把這個屬性關掉就可以規避了。

7.FlatList

FlatList 主要是注意 3 個點:

FlatList 提供自定義的頭部/底部/空白/分割線組件,比一般的 Web 組件封裝更徹底一些React 渲染列表的時候會要求加 key 以提高 diff 性能,但是 FlatList 封裝的比較多,需要用 `keyExtractor`[6] 這個 API 來指定列表 Cell 的 keyFlatList 性能優化的內容官網寫的不是很好,我之前寫了個更易懂的[7],有需求的同學可以了解一下
二、內置 API

本節內容主要是是對官網 React Native API[8] 內容的補充,主要是說一些讓人開發體驗不爽的地方,幫助後來人避坑。

1.AppState

AppState 這個 API 在實際開發中主要是監聽 APP 前後臺切換的,這個 API 在 iOS 上表現符合語義,但是 Android 上就有問題了,因為 AppState 在 Android 端的實現其實是基於 Activity 的生命周期[9] 的。

就比如說 AppState 提供的 background 這個狀態,其實是基於 Activity 的 onPause()[10] 的,但是根據 Android 的文檔,onPause() 執行時有這麼幾種場景:

當前 RN 容器 Activity 上層覆蓋了新的 Activity(不符合預期)當前 RN 容器 Activity 上層覆蓋了 Dialog,例如權限申請彈窗(Dialog 本質上就是個半透明 Dialog)(不符合預期)

綜上所述,使用 AppState 監聽 APP 狀態時要充分考慮 Android 的這些「異常」表現是否會引起程序 BUG。

2.Permissions

APP 平臺的權限管理是一件很繁瑣的事情,RN 官方只提供了 PermissionsAndroid,沒有提供跨平臺的權限管理 API,使用時很不方便。這裡我建議使用 react-native-permissions[11] 這個庫,管理權限更便捷。

3.Event

RN 官網上沒有暴露 Event 相關的 API,但是 RN 已經對外導出[12]了 DeviceEventEmitter  這個「發布-訂閱」事件管理 API,使用也很簡單,如下案例使用即可。

import { DeviceEventEmitter } from 'react-native';

// 觸發
DeviceEventEmitter.emit('EVENT');
// 監聽
const listener = DeviceEventEmitter.addListener( 'EVENT', () => {});
// 移除
listener.remove()

4.Animated

RN 的動畫 API,說實話掌握成本比較高,單官方 API 就涉及到 Animated、LayoutAnimation、Easing、useNativeDriver 等概念,而且文檔分布比較分散,初學者很難在腦海裡構建一個完整的腦圖。

如果你想構建性能更高的動畫,還得學習 react-native-gesture-handler[13]、react-native-reanimated[14] 等第三方庫的 API,學習成本直線飆升。

這裡我推薦 React Native Animation Book[15] 這本在線書籍,基本上算是手把手教學,看完之後就對 RN 的動畫 API 有個整體的認識了。


三、第三方 Library

React Native 陸陸續續把一些非核心的組件交給社區維護,例如 webview、async-storage 等。還有一些非官方但很好用的組件,例如 react-native-svg、react-native-camera 等等。

除了這些和 Native 相關的第三方庫,JS 社區裡宿主無關的 JS 庫也是可以使用的,例如 lodash、redux 等純邏輯庫。

由於第三方庫太多了,所以我這裡就不一一列舉了。


四、特效篇

React Native 的 style 樣式屬性提供了基礎的布局屬性,例如 flexbox layout、fontSize 等等。但是很多 CSS3 的特效屬性,React Native 基本上都得引入第三方庫。我梳理了一下常用的幾個 UI 特效要用到的屬性和插件,方便開發者使用。

1.圓角效果

這個直接使用 View styles 屬性的 `borderRadius`[16] 即可,RN 同時也支持設置 View 四個角的單獨弧度。

2.模糊效果

blur 效果要用到 @react-native-community/blur[17] 這個 RN 官方社區庫。這個 RN 模糊庫比 CSS 的 blur() 屬性更強大一些,CSS 只支持高斯模糊,這個庫支持起碼三種模糊效果,不過具體效果還是要和 UED 商議。

3.陰影效果

陰影可以用 RN 提供的 `Shadow Props`[18],但是它是分平臺的:

iOS 提供了 shadowColor、shadowOffset、shadowOpacity 和 shadowRadius 四個屬性,和 CSS 的 box-shadow 屬性完全對標,可以滿足絕大多數的場景Android 只提供了 shadowColor 和 `elevation`[19] 兩個屬性,而且從嚴格意義上來說,elevation 其實是「仰角」的意思,是 Android 官方提供的屬性,模擬現實中的從上向下的光照引起的陰影變化。雖然理論一套一套的,但是在現實開發中就會發現,elevation 搞出來的陰影非常醜,和 iOS 比起來完全是天壤之別。個人一般建議使用漸變替代陰影。4.漸變效果

漸變要使用一個第三方庫:react-native-linear-gradient[20],正如庫名,這個倉庫只提供「線性漸變」的解決方案,以個人經驗,線性漸變在絕大部分情況下都足夠了。如果要使用「徑向漸變」,可以使用 react-native-svg[21] 的 RadialGradient  組件。


五、可視化篇

Web 平臺除了最基礎的 <p/> <img/> 標籤,還支持 SVG、canvas 這些自由度較高的繪製 API。它們支持最多的就是可視化場景,例如各種自定義圖像和圖表。下面就簡單介紹一下 RN 中對標 Web 的的一些第三方庫。

1.SVG

RN 的 SVG 支持是基於 react-native-svg[22] 這個倉庫,就個人的使用體驗來說,基本和 Web 的 SVG 功能沒啥兩樣。除了自繪一些自定義 SVG,它更多的功能是作為底層庫支持上層圖表的使用。

2.類 canvas

RN 中是沒有 canvas 這個概念的,市面上也沒有很好用的 canvas 替代品。有開發者搞出了 react-native-skia[23],也有一些 demo 展示[24]。但它目前其實還是一個實驗性項目,上生產環境風險還是太大了。不過就我個人經驗來說,很多繪製功能都能基於 SVG 實現,必須用 canvas 的情況應該並不多見。

📌

基於 skia 你再把 flutter 集成進去,可以玩套娃遊戲了 :)

3.OpenGL 支持

在移動端平臺上,WebGL 就是瀏覽器平臺對 OpenGL ES 的封裝,RN 本身已經很貼近 Native 平臺了,就沒必要捨近求遠支持 WebGL 了,直接支持 OpenGL ES 就好。

目前 RN 對 OpenGL 的支持是基於 gl-react[25] 的,底層的適配層是基於 expo-gl[26]。網上有個 gl-react 的 demo 教程[27],有需要的讀者可以學習一下。

📌

因為個人沒做過 RN 3D 相關的需求,所以也無法對該庫得出一個準確的評價,需要讀者自行判斷

4.圖表功能

圖表是個很現實的需求,在一些 B 端場景上經常會有報表需求。因為 RN 只有 SVG 支持比較完善,所以 RN 的圖表基本都是基於 SVG 繪製的。

Web 上基於 SVG 的圖表庫有很多,但是 RN 能用到的可能沒有幾個。主要原因是 RN 和 Web 的宿主環境不一樣,一些圖表庫可能會用到 Web 特供 API(例如 getElmentById),像 ECharts[28] 這樣的庫 RN 肯定是用不了的。

可遷移使用的庫一般要滿足兩個條件:

純邏輯:D3.js 一些純邏輯的庫,只用到 JS 的語言能力,例如 d3-scale[29]平臺無關:直接基於 React 構建,沒有用到平臺特有 API,例如 victory-native[30]

這裡有一個基於 D3.js 實現的股票箱型圖的視頻教程[31],感興趣的讀者可以了解一下。

5.海報功能

海報分享是現如今非常常見的一個前端功能,網頁基本是基於 canvas 生成分享海報的,RN 雖沒有較好的 canvas API,但是有個不錯的庫——react-native-view-shot[32],可以把 RN 寫的 View 生成一張圖片。借用這個庫就能在 APP 本地生成圖片,轉而實現海報功能。

參考資料[1]

官方文檔 reactnative.dev: https://reactnative.dev/

[2]

React Native Core Components: https://reactnative.dev/docs/components-and-apis

[3]

Ultimate guide to use custom fonts in react native: https://mehrankhandev.medium.com/ultimate-guide-to-use-custom-fonts-in-react-native-77fcdf859cf4

[4]

react-native-webp-format: https://github.com/Aleksefo/react-native-webp-format

[5]

How to hide the statusBar when react-native modal shown?: https://stackoverflow.com/questions/45369688/how-to-hide-the-statusbar-when-react-native-modal-shown

[6]

keyExtractor: https://reactnative.dev/docs/flatlist#keyextractor

[7]

更易懂的: https://supercodepower.com/react_native_performance_optimization_guides#%E5%85%AD%E3%80%81%E9%95%BF%E5%88%97%E8%A1%A8%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96

[8]

React Native API: https://reactnative.dev/docs/accessibilityinfo

[9]

Activity 的生命周期: https://developer.android.com/guide/components/activities/activity-lifecycle#lc

[10]

onPause(): https://developer.android.com/guide/components/activities/activity-lifecycle#onpause

[11]

react-native-permissions: https://github.com/zoontek/react-native-permissions

[12]

對外導出: https://github.com/facebook/react-native/blob/8d0a2e79212b77cafcc9af73e92c0f2b23f782e8/index.js#L416

[13]

react-native-gesture-handler: https://github.com/software-mansion/react-native-gesture-handler#readme

[14]

react-native-reanimated: https://github.com/software-mansion/react-native-reanimated#readme

[15]

React Native Animation Book: https://animationbook.codedaily.io/introduction

[16]

borderRadius: https://reactnative.dev/docs/view-style-props#borderradius

[17]

@react-native-community/blur: https://github.com/Kureev/react-native-blur

[18]

Shadow Props: https://reactnative.dev/docs/shadow-props

[19]

elevation: https://reactnative.dev/docs/view-style-props#elevation-android

[20]

react-native-linear-gradient: https://github.com/react-native-linear-gradient/react-native-linear-gradient

[21]

react-native-svg: https://github.com/react-native-svg/react-native-svg

[22]

react-native-svg: https://github.com/react-native-svg/react-native-svg

[23]

react-native-skia: https://github.com/react-native-skia/react-native-skia

[24]

demo 展示: https://twitter.com/chrfalch/status/1434880480650932232

[25]

gl-react: https://github.com/gre/gl-react

[26]

expo-gl: https://docs.expo.dev/versions/latest/sdk/gl-view/

[27]

demo 教程: https://www.youtube.com/watch?v=rMdLNvVOUEI

[28]

ECharts: https://github.com/apache/echarts

[29]

d3-scale: https://github.com/d3/d3-scale

[30]

victory-native: https://github.com/FormidableLabs/victory-native

[31]

視頻教程: https://www.youtube.com/watch?v=gLsi1IO4BpA

[32]

react-native-view-shot: https://github.com/gre/react-native-view-shot

[33]

🎨 React Native 性能優化——Render 篇: https://supercodepower.com/react_native_performance_optimization_guides

[34]

⚡️ React Native 啟動速度優化——Native 篇: https://supercodepower.com/react-native-performance-native

[35]

⚡️ React Native 啟動速度優化——JS 篇: https://supercodepower.com/react-native-performance-js

相關焦點

  • React Native 已死?
    最近的技術圈尤為熱鬧,Google 發布了首個 Flutter 預覽版、Vue.js 在 GitHub 上的 star 數量超過了 React.js,而如今全球著名的民宿預訂平臺 Airbnb 突然宣布要棄 React Native 坑而逃,回歸原生技術開發,不得不說,這一舉措著實讓 React Native 備受打擊,也讓很多趟過坑的同學們感同身受。
  • 從零到一:用ReactNative開發的第一個跨平臺app
    ": "16.0.0-alpha.6","react-native": "0.44.2","react-native-camera": "^0.6.0",(掃碼)"react-native-deprecated-custom-components": "^0.1.0","react-native-easy-toast": "^1.0.6",
  • 入門 | 從Android到React Native開發
    原生開發在React Native的優勢是後期,React Native隨著業務的增加,單純的React Native時時無法滿足需求,那時候熟悉原生、又掌握了React Native的你,一定能給出更好的解決方案。所以不要放棄(我會告訴你中途我都放棄好幾次了嘛?),萬事開頭難,何況你已經被Android坑了這麼久,怕( ̄ ̄;)什麼?
  • 十大最受歡迎的 React Native 應用開發編輯器
    它為 React Native、Hack 和 Flow 項目提供一流的開發環境。2.Sublime Text 一直是開發人員最喜歡的編輯器。Sublime Text 常用包react-native-snippets - 用於 react native 的 Sublime Text 的片段集合babel-sublime - 具有 React JSX 擴展的 ES6 JavaScript 的語法定義。4.
  • ReactNative學習資源大匯集
    /fangwei716/30-days-of-react-nativeReact-Native視頻教程(部分免費) https://egghead.io/technologies/reactReact Native 開發培訓視頻教程(中文|免費)https://www.gitbook.com/book/unbug/react-native-training/details
  • 給所有開發者的React Native詳細入門指南
    現在連幾百元的手機都有指紋識別了。所以如果去年你沒有去關注去學習RN 不要緊,但是隨著微信發布小程序,這再次說明了全棧式前端是一個趨勢,如果你還沒有趁機上車,那……那其實也沒啥,一門心思寫好Android其實也是可以的,畢竟專才也是要有的!哈哈~前面說的有點危言聳聽了,但還是希望那些學有餘力、熱愛並關注前端開發的人能早點搭上這趟車。
  • 如何用 React Native 開發一款電商 App?
    編者按:React Native愈發火爆,如果你尚未接觸過,不如看看本文作者的入門指南,他會帶你體驗基於RN平臺開發一款電子商務搜索類App的奇妙旅程!本文編譯自Hackernoon,原文標題為:Building an e-commerce search app with react native,推薦有一定編程基礎的讀者閱讀。
  • ReactNative從零到完整項目-嵌入到安卓原生應用
    首先當然要了解你要植入的React Native組件。2.  在Android項目根目錄中使用npm來安裝`react-native` ,這樣同時會創建一個`node_modules/`的目錄。3.  創建js文件,編寫React Native組件的js代碼。4.
  • React Native 開發日常、常見問題總結及解決
    建議:Flutter 未來的趨勢,趕緊學,趕緊幹;大公司基本都用上了;方法:可以關注 阿里 相關的 技術公眾號,你能知道目前 熱門技術及乾貨;個人感覺前沿技術基本在 阿里系;跟著大公司的步伐學習不會錯、不會脫軌
  • React Native開發基礎入門之搭建開發環境
    這篇文檔會幫助你搭建基本的 React Native 開發環境。如果你已經搭好了環境,那麼可以嘗試一下編寫 Hello World。完整原生環境Follow these instructions if you need to build native code in your project.
  • ReactNative的調試工具Expo
    很久沒有再寫關於React的文字了,再看看React又有不少變化,從官網的文字中就可以看出無論是Reactjs還是ReactNative都變的越來越簡潔了
  • 怎麼理解React Native的新架構?
    Facebook 在 2018 年 6 月官方宣布了大規模重構 React Native 的計劃及重構路線圖。目的是為了讓 React Native 更加輕量化、更適應混合開發,接近甚至達到原生的體驗。之前我還寫了一篇文章分析了下 Facebook 的設計想法。
  • 環境配置:React Native 開發環境配置 For Android
    起源React Native 是由 React 衍生出來的,而 React 起源於 Facebook 的內部項目,因為FaceBook對市場上所有 JavaScript MVC 框架,都不太滿意,就決定自己寫一套,用來架設自己的 Instagram 的網站。等做出來以後,發現這套東西很不錯,而且好用,就在2013年5月開源了。
  • React Native實戰:配置和起步
    (註:本篇文章 iOS 和 Android 開發都適用。)目前使用 React Native 開發只能在 Mac 系統 上進行。寫 iOS 的同學,應該都是 Mac (除了聽說網易有些部門寫 iOS 給黑蘋果之外,哈哈哈哈)。 開發 Android 的同學, 如果公司配發的不是 Mac 的話,建議自己入手一個,能顯著提高生產力,就當投資自己吧。
  • 最火移動端跨平臺方案盤點:React Native、weex、Flutter
    本篇主要以react-native、weex、flutter,深入聊聊當前最火的這3種跨平臺移動開發方案的實現原理、現狀與未來。至於為什麼只講它們,因為對比ionic、phoneGap,它們更於 「naive」 ( )。看完本篇,相信你會對於當下跨平臺移動開發的現狀、實現原理、框架的選擇等有更深入的理解。
  • Facebook 發布 React Native for Android
    Facebook 今天發布了 React Native for Android,把 Web 和原生平臺的 JavaScript 開發技術擴展到了
  • 推薦11 款 React Native 開源移動 UI 組件
    React Native 是近期 Facebook 基於 MIT 協議開源的原生移動應用開發框架,已經用於 Facebook 的生產環境。React Native 可以使用最近非常流行的 React.js 庫來開發 iOS 和 Android 原生 APP。
  • 用JavaScript開發移動原生應用,Facebook正式開源React Native!
    不過目前,只有iOS版,Android版還需要再等一段時間,這是最新的用JavaScript語言開發原生App的嘗試,其示例代碼相當簡潔,內置控制項也不少。同時還為React Native開發了一款基於Atom的IDE——Nuclide,也已開源。
  • 聊聊React Native屏幕適配那些事兒
    往期精彩RN文章推薦:-【從源碼分析】可能是全網最實用的React Native異常解決方案【建議收藏】適合閱讀群體有一定RN開發經驗,了解RN js 模塊如何與原生模塊通信;為什麼需要適配保證界面在不同的設備屏幕上都能按設計圖效果展示,統一用戶視覺與操作體驗常見適配名詞闡述如果你從網上去搜屏幕適配,你搜到的博文中一定都會有以下一大堆名詞及其解釋
  • 分享 50 個完整的 React Native 項目
    下面直奔主題↓↓↓項目名稱:react-native-eyepetizer項目地址:https://github.com/MarnoDev/react-native-eyepetizer項目簡介:模仿開眼