📝 沒 2 年 React Native 開發經驗,你都遇不到這些坑
- 2021 年 9 月 28 日
- 筆記
- React, react native, 前端, 跨端開發
📌
如果你喜歡我的文章,希望點贊👍 收藏 📁 評論 💬 三連支援一下,謝謝你,這對我真的很重要!
React Native 開發時,如果只是寫些簡單的頁面,基本上按著官方文檔 reactnative.dev就能寫出來,但是 React Native 的 API 有幾百個,沒有一定的開發踩坑經驗,面對一些新的需求時確實會抓不到重點。
本文總結了我個人開發 React Native 中遇到的問題和一些冷門的 API,如果有有緣人看到這篇文章並解決了實際問題,那就最好不過了。
一、內置組件
本節內容主要是是對官網 React Native Core Components 內容的補充,主要是說一些讓人開發體驗不爽的地方,幫助後來人避坑。
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.TextInput
輸入框組件也是很常用的屬性,個人用下來有幾個不爽的地方:
-
iOS/Android 的默認樣式差距比較大,不做封裝的話會寫非常多的平台相關程式碼
-
placeholder
的文字比較長時,若出現換行現象,沒有 API 去控制它的行高 -
若一個頁面出現多個
TextInput
組件時,需要用ScrollView
組件包裹,才能實現不同TextInput
組件焦點切換的功能
4.Image
Image 組件在表現上我個人認為非常優秀了,但在一些細節上初步上手的同學可能還是不太習慣:
-
沒有 CSS 那麼多的濾鏡屬性,只支援模糊效果,不過個人基本沒遇到過影像濾鏡需求 -
載入網路圖片時,必須指定圖片寬高,若不設置尺寸默認為 0 -
Android 上圖片尺寸非常大時(貌似是 5000px?),圖片會直接載入不出來,不過這種場景很少很少,基本都會瓦片圖分步載入,要不然大圖會引起 OOM 的 -
iOS/Android 對 webp 的支援也不是開箱即用的,需要分別配置: -
iOS 使用 SDImageWebPCoder
提供支援 -
Android 使用 fresco
提供支援 -
具體配置方案可以參考 react-native-webp-format
-
-
Android 不支援點九圖
5.Modal
RN 官方之前提供的 Modal 組件有個很明顯的問題,Modal 無法覆蓋到狀態欄。比如說我們做了一個彈窗,背景是黑色半透明的,但狀態欄是白色的,這樣在感官上就非常的割裂。
所幸 0.62 版本上了一個 statusBarTranslucent
屬性,設為 true 就可以覆蓋到狀態欄之上。如果是 0.62 以下的版本,就需要改一些配置了,可以參考 stackoverflow 的這個回答:How to hide the statusBar when react-native modal shown?
6.ScrollView
ScrollView 組件是 RN 提供的滑動容器組件,有幾個比較冷門但是很好用的 API 我這裡說明一下。
第一個是吸頂功能,涉及到 StickyHeaderComponent
和 stickyHeaderIndices
這兩個 API,可以實現滾動吸頂的效果,非常的好用。
第二個是 automaticallyAdjustContentInsets
屬性,有時候 iOS 滾動列表上會出現莫名其妙的空白區域,這個是 iOS Native 層實現的,RN 具體的觸發時機我沒有做詳細的測試,但基本上把這個屬性關掉就可以規避了。
7.FlatList
FlatList 主要是注意 3 個點:
-
FlatList 提供自定義的頭部/底部/空白/分割線組件,比一般的 Web 組件封裝更徹底一些 -
React 渲染列表的時候會要求加 key
以提高 diff 性能,但是 FlatList 封裝的比較多,需要用keyExtractor
這個 API 來指定列表 Cell 的key
-
FlatList 性能優化的內容官網寫的不是很好,我之前寫了個更易懂的,有需求的同學可以了解一下
二、內置 API
本節內容主要是是對官網 React Native API 內容的補充,主要是說一些讓人開發體驗不爽的地方,幫助後來人避坑。
1.AppState
AppState 這個 API 在實際開發中主要是監聽 APP 前後台切換的,這個 API 在 iOS 上表現符合語義,但是 Android 上就有問題了,因為 AppState 在 Android 端的實現其實是基於 Activity 的生命周期 的。
就比如說 AppState 提供的 background
這個狀態,其實是基於 Activity 的 onPause() 的,但是根據 Android 的文檔,onPause()
執行時有這麼幾種場景:
-
APP 切換到系統後台(符合預期) -
當前 RN 容器 Activity 上層覆蓋了新的 Activity(不符合預期) -
當前 RN 容器 Activity 上層覆蓋了 Dialog,例如許可權申請彈窗(Dialog 本質上就是個半透明 Dialog)(不符合預期)
綜上所述,使用 AppState 監聽 APP 狀態時要充分考慮 Android 的這些「異常」表現是否會引起程式 BUG。
2.Permissions
APP 平台的許可權管理是一件很繁瑣的事情,RN 官方只提供了 PermissionsAndroid
,沒有提供跨平台的許可權管理 API,使用時很不方便。這裡我建議使用 react-native-permissions 這個庫,管理許可權更便捷。
3.Event
RN 官網上沒有暴露 Event 相關的 API,但是 RN 已經對外導出了 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、react-native-reanimated 等第三方庫的 API,學習成本直線飆升。
這裡我推薦 React Native Animation Book 這本在線書籍,基本上算是手把手教學,看完之後就對 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
即可,RN 同時也支援設置 View 四個角的單獨弧度。
2.模糊效果
blur 效果要用到 @react-native-community/blur 這個 RN 官方社區庫。這個 RN 模糊庫比 CSS 的 blur()
屬性更強大一些,CSS 只支援高斯模糊,這個庫支援起碼三種模糊效果,不過具體效果還是要和 UED 商議。
3.陰影效果
陰影可以用 RN 提供的 Shadow Props
,但是它是分平台的:
-
iOS 提供了 shadowColor
、shadowOffset
、shadowOpacity
和shadowRadius
四個屬性,和 CSS 的 box-shadow 屬性完全對標,可以滿足絕大多數的場景 -
Android 只提供了 shadowColor
和elevation
兩個屬性,而且從嚴格意義上來說,elevation
其實是「仰角」的意思,是 Android 官方提供的屬性,模擬現實中的從上向下的光照引起的陰影變化。雖然理論一套一套的,但是在現實開發中就會發現,elevation
搞出來的陰影非常丑,和 iOS 比起來完全是天壤之別。個人一般建議使用漸變替代陰影。
4.漸變效果
漸變要使用一個第三方庫:react-native-linear-gradient,正如庫名,這個倉庫只提供「線性漸變」的解決方案,以個人經驗,線性漸變在絕大部分情況下都足夠了。如果要使用「徑向漸變」,可以使用 react-native-svg 的 RadialGradient
組件。
五、可視化篇
Web 平台除了最基礎的 <p/>
<img/>
標籤,還支援 SVG、canvas 這些自由度較高的繪製 API。它們支援最多的就是可視化場景,例如各種自定義影像和圖表。下面就簡單介紹一下 RN 中對標 Web 的的一些第三方庫。
1.SVG
RN 的 SVG 支援是基於 react-native-svg 這個倉庫,就個人的使用體驗來說,基本和 Web 的 SVG 功能沒啥兩樣。除了自繪一些自定義 SVG,它更多的功能是作為底層庫支援上層圖表的使用。
2.類 canvas
RN 中是沒有 canvas 這個概念的,市面上也沒有很好用的 canvas 替代品。有開發者搞出了 react-native-skia,也有一些 demo 展示。但它目前其實還是一個實驗性項目,上生產環境風險還是太大了。不過就我個人經驗來說,很多繪製功能都能基於 SVG 實現,必須用 canvas 的情況應該並不多見。
📌
基於 skia 你再把 flutter 集成進去,可以玩套娃遊戲了 🙂
3.OpenGL 支援
在移動端平台上,WebGL 就是瀏覽器平台對 OpenGL ES 的封裝,RN 本身已經很貼近 Native 平台了,就沒必要捨近求遠支援 WebGL 了,直接支援 OpenGL ES 就好。
目前 RN 對 OpenGL 的支援是基於 gl-react 的,底層的適配層是基於 expo-gl。網上有個 gl-react 的 demo 教程,有需要的讀者可以學習一下。
📌
因為個人沒做過 RN 3D 相關的需求,所以也無法對該庫得出一個準確的評價,需要讀者自行判斷
4.圖表功能
圖表是個很現實的需求,在一些 B 端場景上經常會有報表需求。因為 RN 只有 SVG 支援比較完善,所以 RN 的圖表基本都是基於 SVG 繪製的。
Web 上基於 SVG 的圖表庫有很多,但是 RN 能用到的可能沒有幾個。主要原因是 RN 和 Web 的宿主環境不一樣,一些圖表庫可能會用到 Web 特供 API(例如 getElmentById
),像 ECharts 這樣的庫 RN 肯定是用不了的。
可遷移使用的庫一般要滿足兩個條件:
-
純邏輯: D3.js
一些純邏輯的庫,只用到 JS 的語言能力,例如 d3-scale -
平台無關:直接基於 React 構建,沒有用到平台特有 API,例如 victory-native
這裡有一個基於 D3.js 實現的股票箱型圖的影片教程,感興趣的讀者可以了解一下。
5.海報功能
海報分享是現如今非常常見的一個前端功能,網頁基本是基於 canvas 生成分享海報的,RN 雖沒有較好的 canvas API,但是有個不錯的庫——react-native-view-shot,可以把 RN 寫的 View 生成一張圖片。借用這個庫就能在 APP 本地生成圖片,轉而實現海報功能。
推薦閱讀
RN 性能優化系列目錄:
📌
如果你喜歡我的文章,希望點贊👍 收藏 📁 在看 🌟 三連支援一下,謝謝你,這對我真的很重要!
歡迎大家關注我的微信公眾號:滷蛋實驗室,目前專註前端技術,對圖形學也有一些微小研究。
也可以加我的微信 egg_labs,歡迎大家來撩。
