RN 经验

每天一点点
1
1. 创建指定版本

react-native init demo --version 0.55.4 指定版本

2. 跨页面传值
  • DeviceEventEmitter事件传值 <类似通知>
// 引入
import {
    ...
     DeviceEventEmitter
 } form 'react-native';
//发送事件的页面
 DeviceEventEmitter.emit('userNameDidChange', '传值');
//需要接收事件的页面 
componentDidMount() {
     this.subscription = DeviceEventEmitter.addListener('userNameDidChange',(userName) =>{
          alert(userName);
     })
}

//页面卸载  移除事件
componentWillUnmount() {
    this.subscription.remove();
}
3. import 导入的几种方式
  1. import Home from './src/Home';
    导入‘src/Home’文件里export的带default关键字的组件,即默认组件

2.import { Home,Me } from './src/Home';
导入‘src/Home’文件里export的叫Home和Me的非默认组件,可以导入多个组件,用逗号隔开即可

3.import * as Home from'./src/Home';
意思是将./src/Home'文件里的所有非默认组件,全部集结成一个Home模型组件,命名可以自定义,然后可以通过点语法,来使用组件里面的所有export的组件, 如 Home.A 、Home.B

4. 调用打电话功能

Linking提供了一个通用的接口来与传入和传出的App链接进行交互,比如跳转外部链接,打电话,发邮件,打开某个浏览器链接等

//导入Linking
import {
  ...
  Linking
} from "react-native";

...
call(){
  let url = 'tel: ' + '电话号码';
  //let url = "mqqwpa://im/chat?chat_type=wpa&uin=QQ号";//调用QQ
  Linking.canOpenURL(url).then(supported => {
      if (!supported) {
        console.log('Can\'t handle url: ' + url);
      } else {
        Linking.openURL(url);
      }
  }).catch(err => console.error('An error occurred', err));
}
5. 复制到剪贴板
//导入Clipboard
import {
  ...
  Clipboard
} from "react-native";

//复制电话号码到剪贴板
    async _setClipboardContent(tel){
        Clipboard.setString(tel);
        try {
            var content = await Clipboard.getString();
            console.log('复制的手机号:');
            this.clearClose();
            console.log(content);
            
        } catch (e) {
            console.log(e.message)
        }
    }

6. react-navigation 隐藏/显示tabBar
const Tab = TabNavigator(
    {
        Home: {
            screen: HomeScreen,
             /*  TabBar是否显示/隐藏    */
             navigationOptions: ({ navigation }) => {
                // console.log('nav state:', navigation.state);
                 const homeRoute = navigation.state.params;
                 return {
                     /**
                      * 控制tabBar是否显示/隐藏 
                      * 在HomeScreen 页面通过 this.props.navigation.setParams({ tabBarVisible: false/true })控制--
                      */
                     tabBarVisible: homeRoute && homeRoute.tabBarVisible, 
                 }
             }
        },
        ....
    },
    {
        ....
    }
7. 获取Navigator的层级
var currentRoute = this.props.navigator.getCurrentRoutes(); 
for(var i = 0 ; i <currentRoute.length ; i ++){
    if (currentRoute[i].name == '你想跳转的页面'){
        this.props.navigator.popToRoute(currentRoute[i]);
    }
}
8. ImageBackground 的圆角在 style 里设置没用 需要用imageStyle
<ImageBackground style={styles.image}  imageStyle={{borderRadius:10}} />
9. 使得任何一个React组件支持动画。

Animated.createAnimatedComponent(Component: any)可以使任何一个React组件支持动画。 默认支持的Animated.Image,Animated.ScrollView,Animated.Text,Animated.View。

Animated FlatList需使用ref属性时 加入以下代码:

   <Animated.FlatList
       ref={(ref) => { this._listRef = ref}}
       ...
   /> 

   //使用方法
   this._listRef.getNode().scrollToOffset({y:0})
10. view 三角冒泡框
        // 设置上下越小,三角就越尖
          <View style={{
              width: 0,
              height: 0,
              borderTopWidth: 7,
              borderTopColor: 'transparent',
              borderRightWidth: 10,
              borderRightColor: 'red',
              borderLeftWidth: 10,
              borderLeftColor: 'transparent',
              borderBottomWidth: 7,
              borderBottomColor: 'transparent',
           }} />
11. android环境下gif没有动画,不支持gif图

解决:
在android/app/build.gradle中的dependencies字段中添加:
compile 'com.facebook.fresco:fresco:1.5.0'
compile 'com.facebook.fresco:animated-gif:1.5.0'

12. 性能调试及优化

开发模式 (dev=true)

有个小技巧可以在发布时屏蔽掉所有的console.*调用。React Native中有一个全局变量__DEV__用于指示当前运行环境是否是开发环境。我们可以据此在正式环境中替换掉系统原先的console实现。

  if(!__DEV__ ){
      global.console={
         log:() => {},
         info:() => {},
         assert: () => {},
         warn:() => {},
         debug:() => {},
         error:() => {}
      }
  }

_DEV_=true即开发模式下,JavaScript线程的性能是很糟糕的,因为有许多工作需要在运行的时候去做,譬如使你获得良好的警告和错误信息,又比如验证属性类型(propTypes)以及产生各种其他的警告。

13. 使用webview加载html乱码问题
  <WebView 
      ...
      source={{uri:this.state.html, baseUrl:''}}   // baseUrl:'' 中文乱码解决
  />
14. 字体不随系统字体设置改变而改变

方法一:

  const {fontScale} = Dimensions.get('screen');
  fontSize: 20*(1.0/fontScale)

方法二:

import { Text, TextInput } from 'react-native'

TextInput.defaultProps = Object.assign({}, TextInput.defaultProps, {defaultProps: false});
Text.defaultProps = Object.assign({}, Text.defaultProps, {allowFontScaling: false});
15. xcode10.1 0.55.4-0.56 'config.h' file not found

error:Build input file cannot be found: '/Users/taocong/Desktop/RNProject/AppDemo/node_modules/react-native/third-party/

cd node_modules/react-native/third-party/glog-0.3.4
../../scripts/ios-configure-glog.sh
16.通过findNodeHandle和UIManager来获取组件的尺寸:
import {
    findNodeHandle,
    UIManager
} from 'react-native';
 
layout(ref) {
        const handle = findNodeHandle(ref);
         
        return new Promise((resolve) => {
            UIManager.measure(handle, (x, y, width, height, pageX, pageY) => {
                resolve({
                    x,
                    y,
                    width,
                    height,
                    pageX,
                    pageY
                });
            });
        });
 }

layout这个函数接受一个ref参数,这个参数表示组件的实例。传入组件的实例后,然后通过findNodeHandle方法获取组件节点。
UIManager.measure接受两个参数,第一个参数是通过findNodeHandle获取的组件节点,第二个参数是获取成功的回调,回调有6个参数:x,y表示组件的相对位置,width,height表示组件的宽度和高度,pageX,pageY表示组件相对于屏幕的绝对位置。

17.PanResponder

onPanResponderMoveAnimated.event() 的结合使用

利用 PanResponder 做了一个拖动调节图标位置的功能,网上找的方法是在 onPanResponderMove 中使用 Animated.event() 来对 View 进行移动。实现效果不错,但是发现一旦在 onPanResponderMove 中使用了 lambda 表达式后,就不起作用了。后来网上找到这个 issue,发现原来 Animated.event() 会返回一个方法,并且接收 event 和 gestureState 作为参数,所以我们只要去调用一下这个方法即可:

onPanResponderMove: (evt, gestureState) => {
  return Animated.event([null, {
    dx: this.state.pan.x,
    dy: this.state.pan.y,
  }])(evt, gestureState)
}
18.TextInput Android 文字对齐问题

当 TextInput multiline为true,发现文字显示在 iOS 上是顶端对齐,而在 Android 上则文本默认会垂直居中,可设置textAlignVertical: 'top'样式来使其居顶显示。
解决方法 TextInput 设置 textAlignVertical: "top" 属性,相关 issue 见:Render Multiline Text at start instead of center

Android 上 TextInput 失去焦点之后键盘无法自动收起
这时候我们可以给根布局设置接收触摸事件:

onStartShouldSetResponder={() => true}
onResponderRelease={() => Keyboard.dismiss()}

19.KeyboardAvoidingView behavior 相关

该组件在 Android 和 iOS 上的表现有区别,所以我们会区分平台使用不同的 behavior,比如下面这样:

<KeyboardAvoidingView 
    style={styles.container} 
    behavior={Platform.OS === 'android' ? null : 'padding'}
    keyboardVerticalOffset={64}>
    ...
</KeyboardAvoidingView>

padding 模式下,当键盘弹起的时候,你的 view 会向上弹起并被压缩。使用 padding 作为 behavior 的时候,在 iOS 上表现比较好,而在 Android 上则不设置 behavior 比较好。
position 模式下,view 整体会向上滑动。这种模式 Android 和 iOS 上表现一致,但是前提是此时 KeyboardAvoidingView 是根 view。同时这也会造成一个问题,那就是键盘弹出后,输入组件会一直占有焦点,这在安卓上还好,可以通过返回键关闭键盘,而在 iOS 设备上就会造成键盘无法被关闭的尴尬。解决这一问题的方法是通过在 KeyboardAvoidingView 设置接收触摸事件,当在输入焦点之外获得点击时收起键盘:

<KeyboardAvoidingView 
  style={styles.container}
  behavior={'position'}
  onStartShouldSetResponder={(evt) => true}
  onResponderRelease={() => Keyboard.dismiss()}
/>
20. FlatList onEndReached 刷新次数频繁问题
onEndReached={()=>{
  // 等待页面布局完成以后,在让加载更多
   if (this.isCanLoadMore){
      this.loadMore();
      this.isCanLoadMore = false // 加载更多时,不让再次的加载更多
  }
}}
onContentSizeChange={()=>{
  this.isCanLoadMore = true // flatview内部组件布局完成以后会调用这个方法
}}
onEndReachedThreshold={0.01}
21 view阴影
shadowColor: "#000",
shadowOffset: {
    width: 0,
    height: 4,
},
shadowOpacity: 0.30,
shadowRadius: 4.65,
elevation: 8,
22 .解决Modal无法有效隐藏状态栏

编辑android/app/src/main/resvalues/styles/styles.xml

<resources>
    <style  name="AppTheme"    parent="Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen">
    </style>
</resources>
23 .RN离线包准备
  • android
    react-native bundle --entry-file index.js --bundle-output ./android/app/src/main/assets/index.android.bundle --platform android --assets-dest ./android/app/src/main/assets --dev false

  • iOS:
    react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle

  • Duplicate resources报错的话
    在 /node_modules/react-native/react.gradle 这个文件里加上以下代码

doFirst { ... }
doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
    }
    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
}
24. xcode11 0.61.5 react-native-fast-image pod fatal: unable to access 'https://chromium.googlesource.com/webm/libwebp/'
image.png
25. iOS打包

1、RN环境配置:

将命令添加进项目的package.json文件的scripts字段中

"scripts": {

    "bundle-ios": "react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ios/bundle/main.jsbundle --assets-dest ios/bundle"

  }
  • 参数说明:

--entry-file ios或者android入口的js名称,比如index.js

--platform平台名称(ios或者android)

--dev设置为false的时候将会对JavaScript代码进行优化处理。

-- -output 生成的jsbundle文件的名称,比如./ios/bundle/main.jsbundle

--assets-dest图片以及其他资源存放的目录,比如./iOS/bundle

  • 配置完成后

cd ios //进入当前项目文件,进入ios文件夹

mkdir bundle //创建bundle文件夹

打包直接运行npm run bundle-ios

2、Xcode打包

打开iOS工程文件

新增bundle到iOS项目ZLDemo中

选中Xcode项目,鼠标右键选中Add Files to "ZLDemo"添加bundle。

完成后基本所有配置都完成了,之后就是进行iOS在Xcode中配置。

1.1、证书配置

1.2、release配置

1.3、正常Xcode打包流程

1.4、发包自测

备注Xcode打包有问题可以留言一起解决。

问题:ENOENT: no such file or directory open ./ios/bundle/index.ios.jsbundle

缺少 bundle文件,新建。

cd ios //进入当前项目文件,进入ios文件夹

eg:cd /Users/apple/Desktop/ZLDemo/ZLDemo/ios

mkdir bundle //创建bundle文件夹

cd .. //进入上一文件夹(当前项目文件夹)

npm run bundle-ios

react-native bundle --entry-file index.ios.js --bundle-output ./ios/bundle/index.ios.jsbundle --platform ios --assets-dest ./ios/bundle --dev false
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,048评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,184评论 6 345
  • 当忙碌的一天结束了,回到家一个人沉静的时候,总会思考些什么。 清早吃完早餐,检查了网络,就去游泳,这是我这段时间的...
    寒江独钓客阅读 635评论 0 0
  • 如玄关 浅色调的巧笑嫣然,美观性与功用的巧妙结合。 玄关 不一味好高骛远,入户玄关区大量柜体的设置,在日后居住中会...
    泊焉未兆阅读 148评论 0 0
  • 讲两个故事。发生在我自己身上。让我气愤许久的同时迅速成长。 进入职场三年,但职业的特殊性让我丝毫不提防外人。 ...
    萌黄阅读 282评论 0 1