日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ReactNative开发笔记(持续更新...)

發布時間:2024/8/26 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ReactNative开发笔记(持续更新...) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文均為RN開發過程中遇到的問題、坑點的分析及解決方案,各問題點之間無關聯,希望能幫助讀者少走彎路,持續更新中... (2019年3月29日更新)

原文鏈接:http://www.kovli.com/2018/06/25/rn-anything/

作者:Kovli

- 如何在原生端(iOS和android兩個平臺)使用ReactNative里的本地圖片(路徑類似require('./xxximage.png'))。

在ReactNative開發過程中,有時需要在原生端顯示RN里的圖片,這樣的好處是可以通過熱更新來更新APP里的圖片,而不需要發布原生版本,而ReactNative里圖片路徑是相對路徑,類似'./xxximage.png'的寫法,原生端是無法解析這類路徑,那么如果將RN的圖片傳遞給原生端呢?

解決方案

1、圖片如果用網絡圖,那只需要將url字符串地址傳遞給原生即可,這種做法需要時間和網絡環境加載圖片,不屬于本地圖片,不是本方案所追求的最佳方式。

2、懶人做法是把RN的本地圖片生成base64字符串然后傳遞給原生再解析,這種做法如果圖片太大,字符串會相當長,同樣不認為是最佳方案。

其實RN提供了相關的解決方法,如下:

RN端

const myImage = require('./my-image.png'); const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource'); const resolvedImage = resolveAssetSource(myImage); NativeModules.NativeBridge.showRNImage(resolvedImage);

iOS端

#import <React/RCTConvert.h>RCT_EXPORT_METHOD(showRNImage:(id)rnImageData){dispatch_async(dispatch_get_main_queue(), ^{UIImage *rnImage = [RCTConvert UIImage:rnImageData];...}); }

安卓端

第一步,從橋接文件獲取到uri地址

@ReactMethod public static void showRNImage(Activity activity, ReadableMap params){String rnImageUri;try {//圖片地址rnImageUri = params.getString("uri");Log.i("Jumping", "uri : " + uri);...} catch (Exception e) {return;}}

第二步,創建JsDevImageLoader.java

package com.XXX;import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.StrictMode; import android.support.annotation.NonNull; import android.util.Log;import com.XXX.NavigationApplication;import java.io.IOException; import java.net.URL;public class JsDevImageLoader {private static final String TAG = "JsDevImageLoader";public static Drawable loadIcon(String iconDevUri) {try {StrictMode.ThreadPolicy threadPolicy = StrictMode.getThreadPolicy();StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitNetwork().build());Drawable drawable = tryLoadIcon(iconDevUri);StrictMode.setThreadPolicy(threadPolicy);return drawable;} catch (Exception e) {Log.e(TAG, "Unable to load icon: " + iconDevUri);return new BitmapDrawable();}}@NonNullprivate static Drawable tryLoadIcon(String iconDevUri) throws IOException {URL url = new URL(iconDevUri);Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());return new BitmapDrawable(NavigationApplication.instance.getResources(), bitmap);} }

第三步,導入ResourceDrawableIdHelper.java

package com.xg.navigation.react;// Copyright 2004-present Facebook. All Rights Reserved.import android.content.Context; import android.graphics.drawable.Drawable; import android.net.Uri;import com.facebook.common.util.UriUtil;import java.util.HashMap; import java.util.Map;import javax.annotation.Nullable;/*** Direct copy paste from react-native, because they made that class package scope. -_-"* Can be deleted in react-native ^0.29*/ public class ResourceDrawableIdHelper {public static final ResourceDrawableIdHelper instance = new ResourceDrawableIdHelper();private Map<String, Integer> mResourceDrawableIdMap;public ResourceDrawableIdHelper() {mResourceDrawableIdMap = new HashMap<>();}public int getResourceDrawableId(Context context, @Nullable String name) {if (name == null || name.isEmpty()) {return 0;}name = name.toLowerCase().replace("-", "_");if (mResourceDrawableIdMap.containsKey(name)) {return mResourceDrawableIdMap.get(name);}int id = context.getResources().getIdentifier(name,"drawable",context.getPackageName());mResourceDrawableIdMap.put(name, id);return id;}@Nullablepublic Drawable getResourceDrawable(Context context, @Nullable String name) {int resId = getResourceDrawableId(context, name);return resId > 0 ? context.getResources().getDrawable(resId) : null;}public Uri getResourceDrawableUri(Context context, @Nullable String name) {int resId = getResourceDrawableId(context, name);return resId > 0 ? new Uri.Builder().scheme(UriUtil.LOCAL_RESOURCE_SCHEME).path(String.valueOf(resId)).build() : Uri.EMPTY;} }

第四步,創建BitmapUtil.java

package com.XXX;import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.provider.MediaStore; import android.text.TextUtils;import com.XXX.NavigationApplication; import com.XXX.JsDevImageLoader; import com.XXX.ResourceDrawableIdHelper;import java.io.IOException;public class BitmapUtil {private static final String FILE_SCHEME = "file";public static Drawable loadImage(String iconSource) {if (TextUtils.isEmpty(iconSource)) {return null;}if (NavigationApplication.instance.isDebug()) {return JsDevImageLoader.loadIcon(iconSource);} else {Uri uri = Uri.parse(iconSource);if (isLocalFile(uri)) {return loadFile(uri);} else {return loadResource(iconSource);}}}private static boolean isLocalFile(Uri uri) {return FILE_SCHEME.equals(uri.getScheme());}private static Drawable loadFile(Uri uri) {Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());return new BitmapDrawable(NavigationApplication.instance.getResources(), bitmap);}private static Drawable loadResource(String iconSource) {return ResourceDrawableIdHelper.instance.getResourceDrawable(NavigationApplication.instance, iconSource);}public static Bitmap getBitmap(Activity activity, String uri) {if (activity == null || uri == null || TextUtils.isEmpty(uri)) {return null;}Uri mImageCaptureUri;try {mImageCaptureUri = Uri.parse(uri);} catch (Exception e) {e.printStackTrace();return null;}if (mImageCaptureUri == null) {return null;}Bitmap bitmap = null;try {bitmap = MediaStore.Images.Media.getBitmap(activity.getContentResolver(), mImageCaptureUri);} catch (IOException e) {e.printStackTrace();return null;}return bitmap;} }

第五步,使用第一步里的rnImageUri地址

... BitmapUtil.loadImage(rnImageUri) ...

第六步,顯示圖片

import android.widget.RelativeLayout; import android.support.v7.widget.AppCompatImageView; import android.graphics.drawable.Drawable;... final RelativeLayout item = (RelativeLayout) mBottomBar.getChildAt(i); final AppCompatImageView itemIcon = (AppCompatImageView) item.getChildAt(0); itemIcon.setImageDrawable(BitmapUtil.loadImage(rnImageUri));...

- 升級舊RN版本到目前最新的0.57.8如果采用手動升級需要注意如下。

I upgraded from react-naitve 0.55.4 to react-native 0.57.0 and I get this error
bundling failed: Error: The 'decorators' plugin requires a 'decoratorsBeforeExport' option, whose value must be a boolean. If you are migrating from Babylon/Babel 6 or want to use the old decorators proposal, you should use the 'decorators-legacy' plugin instead of 'decorators'.

解決方案:參考如下例子

First install the new proposal decorators with npm install @babel/plugin-proposal-decorators --save-dev or yarn add @babel/plugin-proposal-decorators --dev

Then, inside of your .babelrc file, change this:

{"presets": ["react-native"],"plugins": ["transform-decorators-legacy"] } To this:{"presets": ["module:metro-react-native-babel-preset","@babel/preset-flow"],"plugins": [["@babel/plugin-proposal-decorators", { "legacy" : true }]] }

EDIT:

After you've updated your .babelrc file, make sure to add preset-flow as well with the command yarn add @babel/preset-flow --dev or npm install @babel/preset-flow --save-dev

- ReactNative輸入框TextInput點擊彈起鍵盤,如果鍵盤遮擋了重要位置,如何讓界面自動跟隨鍵盤調整?

使用這個組件KeyboardAvoidingView

本組件用于解決一個常見的尷尬問題:手機上彈出的鍵盤常常會擋住當前的視圖。本組件可以自動根據鍵盤的位置,調整自身的position或底部的padding,以避免被遮擋。

解決方案:參考如下例子

<ScrollView style={styles.container}><KeyboardAvoidingView behavior="position" keyboardVerticalOffset={64}>...<TextInput />...</KeyboardAvoidingView></ScrollView>

- ReactNative輸入框TextInput點擊彈起鍵盤,然后點擊其他子組件,例如點擊提交按鈕,會先把鍵盤收起,再次點擊提交按鈕才響應提交按鈕,得點擊兩次,如何做到點擊提交按鈕的同時收起鍵盤并響應按鈕?

這個問題關鍵在ScrollView的keyboardShouldPersistTaps屬性
,首先TextInput的特殊性(有鍵盤彈起)決定了其最好包裹在ScrollView里,其次如果當前界面有軟鍵盤,那么點擊scrollview后是否收起鍵盤,取決于keyboardShouldPersistTaps屬性的設置。(譯注:很多人反應TextInput無法自動失去焦點/需要點擊多次切換到其他組件等等問題,其關鍵都是需要將TextInput放到ScrollView中再設置本屬性)

  • 'never'(默認值),點擊TextInput以外的子組件會使當前的軟鍵盤收起。此時子元素不會收到點擊事件。
  • 'always',鍵盤不會自動收起,ScrollView也不會捕捉點擊事件,但子組件可以捕獲。
  • 'handled',當點擊事件被子組件捕獲時,鍵盤不會自動收起。這樣切換TextInput時鍵盤可以保持狀態。多數帶有TextInput的情況下你應該選擇此項。
  • false,已過期,請使用'never'代替。
  • true,已過期,請使用'always'代替。

解決方案:看如下例子

<ScrollView style={styles.container}keyboardShouldPersistTaps="handled"><TextInput />...</ScrollView>//按鈕點擊事件注意收起鍵盤_checkAndSubmit = () => {Keyboard.dismiss();};

- ReactNative本地圖片如何獲取其base64編碼?(一般指采用<Image source={require('./icon.png'.../>這類相對路徑地址的圖片資源如何獲取到絕對路徑)

關鍵是要獲取到本地圖片的uri,用到了Image.resolveAssetSource方法,ImageEditor.cropImage方法和ImageStore.getBase64ForTag方法,具體可以查詢官方文檔

解決方案:看如下代碼

import item from '../../images/avator_upload_icon.png';const info = Image.resolveAssetSource(item);ImageEditor.cropImage(info.uri, {size: {width: 126,height: 126},resizeMode: 'cover'}, uri => {ImageStore.getBase64ForTag(uri, base64ImageData => {// 獲取圖片字節碼的base64字符串this.setState({avatarBase64: base64ImageData});}, err => {console.warn("ImageStoreError" + JSON.stringify(err));});}, err => {console.warn("ImageEditorError" + JSON.stringify(err));});

- ReactNative如何讀取iOS沙盒里的圖片?

解決方案:看如下代碼

let RNFS = require('react-native-fs');<Imagestyle={{width:100, height:100}}source={{uri: 'file://' + RNFS.DocumentDirectoryPath + '/myAwesomeSubDir/my.png', scale:1}}

- ReactNative如何做到圖片寬度不變,寬高保持比例,高度自動調整。

RN圖片均需要指定寬高才會顯示,如果圖片數據的寬高不定,但又希望寬度保持不變、不同圖片的高度根據比例動態變化,就需要用到下面這個庫,業務場景常用于文章、商品詳情的多圖展示。

解決方案:使用react-native-scalable-image

從0.44版本開始,Navigator被從react native的核心組件庫中剝離到了一個名為react-native-deprecated-custom-components的單獨模塊中。如果你需要繼續使用Navigator,則需要先npm i facebookarchive/react-native-custom-components安裝,然后從這個模塊中import,即import { Navigator } from 'react-native-deprecated-custom-components'

如果報錯如下參考下面的解決方案

React-Native – undefined is not an object (“evaluating _react3.default.PropTypes.shape”)

解決方案

如果已經安裝了,先卸載npm uninstall --save react-native-deprecated-custom-components

用下面的命令安裝
npm install --save https://github.com/facebookarchive/react-native-custom-components.git

在我們使用Navigator的js文件中加入下面這個導入包就可以了。

import { Navigator } from'react-native-deprecated-custom-components';(注意最后有一個分號)

就可以正常使用Navigator組件了。

- ReactNative開發的APP啟動閃白屏問題

由于處理JS需要時間,APP啟動會出現一閃而過白屏,可以通過啟動頁延遲加載方法來避免這類白屏,可以用下面的庫
解決方案:react-native-splash-screen

- ReactNative如何做到無感熱更新

無論是整包熱更新還是差量熱更新,均需要最終替換JSBundle等文件來完成更新過程,實現原理是js來控制啟動頁的消失時間,等原生把bundle包下載(或合并成新bundle包)解壓到目錄以后,通知js消失啟動頁,由于熱更新時間一般很短,建議使用差量熱更新,一秒左右,所以用戶等啟動頁消失后看到的就是最新的版本。
解決方案(以整包更新為例):

  • 原生端完成更新及刷新操作,注意里面的[_bridge reload]
  • //前往更新js包 RCT_EXPORT_METHOD(gotoUpdateJS:(NSString *)jsUrl andResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject){if (!jsUrl) {return;}//jsbundle更新采用靜默更新//更新NSLog(@"jsbundleUrl is : %@", jsUrl);[[LJFileHelper shared] downloadFileWithURLString:jsUrl finish:^(NSInteger status, id data) {if(status == 1){NSLog(@"下載完成");NSError *error;NSString *filePath = (NSString *)data;NSString *desPath = [NSString stringWithFormat:@"%@",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]];[SSZipArchive unzipFileAtPath:filePath toDestination:desPath overwrite:YES password:nil error:&error];if(!error){[_bridge reload];resolve([NSNumber numberWithBool:true]);NSLog(@"解壓成功");}else{resolve([NSNumber numberWithBool:false]);NSLog(@"解壓失敗");}}}];reject = nil; }
  • JS端
  • // 原生端通過回調結果通知JS熱更新情況,JS端 UpdateModule.gotoUpdateJS(jsUrl).then(resp => {if ( resp ) {// 成功更新通知隱藏啟動頁DeviceEventEmitter.emit("hide_loading_page",'hide');} else {// 出問題也要隱藏啟動頁,用戶繼續使用舊版本DeviceEventEmitter.emit("hide_loading_page",'hide');// 其他處理}});
  • 啟動頁消失,用戶看到的是新版APP
  • async componentWillMount() {this.subscription = DeviceEventEmitter.addListener("hide_loading_page", this.hideLoadingPage);appUpdateModule.updateJs();}hideLoadingPage = ()=> {SplashScreen.hide();};

    注意做好容錯,例如弱網無網環境下的處理,熱更新失敗下次保證再次熱更新的處理,熱更新時間把控,超過時間下次再reload,是否將熱更新reload權利交給用戶等等都可以擴展。

    - ReactNative如何取消部分警告

    debug模式下調試經常會有黃色的警告,有些警告可能是短時間不需要處理,通過下面的解決方法能忽略部分警告提示

    解決方案:使用console.ignoredYellowBox

    import { AppRegistry } from 'react-native'; import './app/Common/SetTheme' import './app/Common/Global'import App from './App';console.ignoredYellowBox = ['Warning: BackAndroid is deprecated. Please use BackHandler instead.','source.uri should not be an empty string','Remote debugger is in a background tab which','Setting a timer','Encountered two children with the same key,','Attempt to read an array index', ];AppRegistry.registerComponent('ReactNativeTemplate', () => App);

    - ReactNative開發遇到android網絡圖片顯示不出來的問題

    開發過程中有時會遇到iOS圖片正常顯示,但是安卓卻只能顯示部分網絡圖片,造成這個的原因有多種,參考下面的解決方案。

    解決方案

  • 安卓增加resizeMethod屬性并設置為resize
  • <Image style={styles.imageStyle} source={{uri: itemInfo.imageUrl || ''}} resizeMethod={'resize'}/>

    resizeMethod官方解釋

    resizeMethod enum('auto', 'resize', 'scale') 當圖片實際尺寸和容器樣式尺寸不一致時,決定以怎樣的策略來調整圖片的尺寸。默認值為auto。auto:使用啟發式算法來在resize和scale中自動決定。resize: 在圖片解碼之前,使用軟件算法對其在內存中的數據進行修改。當圖片尺寸比容器尺寸大得多時,應該優先使用此選項。scale:對圖片進行縮放。和resize相比, scale速度更快(一般有硬件加速),而且圖片質量更優。在圖片尺寸比容器尺寸小或者只是稍大一點時,應該優先使用此選項。關于resize和scale的詳細說明請參考http://frescolib.org/docs/resizing-rotating.html.
  • 如果是FlatList或ScrollView等包裹圖片,嘗試設置
  • removeClippedSubviews={true}//ios set false

  • 如果還是有問題,嘗試配合react-native-image-progress

    還可以謹慎嘗試使用react-native-fast-image

  • - ReactNative判斷及監控網絡情況方法總結

    提前獲取用戶的網絡情況很有必要,RN主要靠NetInfo來獲取網絡狀態,不過隨著RN版本的更新也有一些變化。
    解決方案:

  • 較新的RN版本(大概是0.50及以上版本)
  • this.queryConfig();queryConfig = ()=> {this.listener = NetInfo.addEventListener('connectionChange', this._netChange);};// 網絡發生變化時_netChange = async(info)=> {const {type,//effectiveType} = info;const netCanUse = !(type === 'none' || type === 'unknown' || type === 'UNKNOWN' || type === 'NONE');if (!netCanUse) {this.setState({isNetError : true});this.alertNetError(); //或者其他通知形式} else {try {// 注意這里的await語句,其所在的函數必須有async關鍵字聲明let response = await fetch(CONFIG_URL);let responseJson = await response.json();const configData = responseJson.result;if (response && configData) {this.setState({is_show_tip: configData.is_show_tip,app_bg: CONFIG_HOST + configData.app_bg,jumpUrl: configData.url,isGetConfigData: true}, () => {SplashScreen.hide();})} else {// 錯誤碼也去殼if ( responseJson.code === 400 ) {this.setState({isGetConfigData: true}, () => {SplashScreen.hide();})} else {this.setState({isGetConfigData: false}, () => {SplashScreen.hide();})}}} catch (error) {console.log('queryConfig error:' + error);this.setState({isGetConfigData: true}, () => {SplashScreen.hide();})}}};alertNetError = () => {setTimeout(()=> {SplashScreen.hide();}, 1000);if ( ! this.state.is_show_tip && this.state.isGetConfigData ) {return} else {Alert.alert('NetworkDisconnected','',[{text: 'NetworkDisconnected_OK', onPress: () => {this.checkNetState();}},],{cancelable: false}); }};checkNetState = () => {NetInfo.isConnected.fetch().done((isConnected) => {if ( !isConnected ) {this.alertNetError();} else {this.queryConfig();}});};
  • 老版本
  • async componentWillMount() {this.queryConfig();}checkNetState = () => {NetInfo.isConnected.fetch().done((isConnected) => {console.log('111Then, is ' + (isConnected ? 'online' : 'offline'));if (!isConnected) {this.alertNetError();} else {this.queryConfig();}});};alertNetError = () => {setTimeout(()=> {SplashScreen.hide();}, 1000);console.log('111111');if (!this.state.is_show_tip && this.state.isGetConfigData) {console.log('222222');return} else {console.log('33333');Alert.alert('NetworkDisconnected','',[{text: 'NetworkDisconnected_OK', onPress: () => {this.checkNetState();}},],{cancelable: false});}};queryConfig = ()=> {NetInfo.isConnected.addEventListener('connectionChange',this._netChange);};// 網絡發生變化時_netChange = async(isConnected)=> {console.log('Then, is ' + (isConnected ? 'online' : 'offline'));if (!isConnected) {console.log('666');this.setState({isNetError: true});this.alertNetError();} else {try {// 注意這里的await語句,其所在的函數必須有async關鍵字聲明let response = await fetch(CONFIG_URL);let responseJson = await response.json();const configData = responseJson.result;if (response && configData) {this.setState({is_show_tip: configData.is_show_tip,app_bg: CONFIG_HOST + configData.app_bg,jumpUrl: configData.url,isGetConfigData: true}, () => {SplashScreen.hide();this.componentNext();})} else {this.setState({isGetConfigData: false}, () => {SplashScreen.hide();this.componentNext();})}} catch (error) {console.log('queryConfig error:' + error);this.setState({isGetConfigData: true}, () => {SplashScreen.hide();this.componentNext();})}}};

    - ReactNative版本升級后報錯有廢棄代碼的快速解決方法

    使用第三方庫或者老版本升級時會遇到報錯提示某些方法被廢棄,這時候尋找和替換要花不少時間,而且還容易漏掉。

    解決方案
    根據報錯信息,搜索廢棄的代碼,例如

    報錯提示:Use viewPropTypes instead of View.propTypes.

    搜索命令:grep -r 'View.propTypes' .

    替換搜索出來的代碼即可。

    這是用于查找項目里的錯誤或者被廢棄的代碼的好方法

    - 解決ReactNative的TextInput在0.55中文無法輸入的問題

    此問題主要體現在iOS中文輸入法無法輸入漢字,是0.55版RN的一個bug

    解決方案:使用下面的MyTextInput替換原TextInput

    import React from 'react'; import { TextInput as Input } from 'react-native';export default class MyTextInput extends React.Component {static defaultProps = {onFocus: () => { },};constructor(props) {super(props);this.state = {value: this.props.value,refresh: false,};}shouldComponentUpdate(nextProps, nextState) {if (this.state.value !== nextState.value) {return false;}return true;}componentDidUpdate(prevProps) {if (prevProps.value !== this.props.value && this.props.value === '') {this.setState({ value: '', refresh: true }, () => this.setState({ refresh: false }));}}focus = (e) => {this.input.focus();};onFocus = (e) => {this.input.focus();this.props.onFocus();};render() {if (this.state.refresh) {return null;}return (<Input{...this.props}ref={(ref) => { this.input = ref; }}value={this.state.value}onFocus={this.onFocus}/>);} }

    ReactNative集成第三方DEMO編譯時遇到RCTSRWebSocket錯誤的解決方法

    報錯信息如下

    Ignoring return value of function declared with warn_unused_result attribute

    解決方案

    StackOverFlow上的解決方法:

    在navigator雙擊RCTWebSocket project,移除build settings > custom compiler 下的flags

    版權聲明:

    轉載時請注明作者Kovli以及本文地址:
    http://www.kovli.com/2018/06/25/rn-anything/


    轉載于:https://www.cnblogs.com/kovli/p/rn_anything.html

    總結

    以上是生活随笔為你收集整理的ReactNative开发笔记(持续更新...)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。