RN踩坑记录(持续更新).....

1,192 阅读5分钟

实现富文本

  1. 使用 组件实现

    <Text
        style={{
            marginHorizontal: 16,
            alignItems: 'center',
            justifyContent: 'center'
        }}>
        <Text
            style={[            styles.text,            { color: Palette.blackSubTitle }        ]}>
            {'正常开始文本  '}
        </Text>
        <Text
            style={[            styles.text,            {                color: Palette.green            }        ]}
            onPress={() => {}}>
            {'高亮文本'}
        </Text>
        <Text
            style={[            styles.text,            { color: Palette.blackSubTitle }        ]}>
            {' 正常结束文本'}
        </Text>
    </Text>
    
    
  2. 高亮事件使用 标签包裹在安卓设备会有问题

截屏2022-03-21 下午3.27.45.png

<>
    <Text
        style={[
            styles.text,
            { color: Palette.blackSubTitle }
        ]}>
        {'正常开始文本  '}
    </Text>
    <TouchableOpacity
        activeOpacity={1.0}
        onPress={onCalculatorPress}
        style={{ paddingTop: 3 }}>
        <Text
            style={[
                styles.text,
                {
                    color: Palette.green
                }
            ]}>
            {'高亮文本'}
        </Text>
    </TouchableOpacity>
    <Text
        style={[
            styles.text,
            { color: Palette.blackSubTitle }
        ]}>
        {' 正常结束文本'}
    </Text>
</>

解决办法:使用 transform 修改渲染位置

<Text
    style={[
        styles.text,
        {
            color: Palette.green,
            transform: [
                {
                    translateY:
                        Platform.OS ===
                        'android'
                            ? 5
                            : 0
                }
            ]
        }
    ]}>
    {'高亮文本'}
</Text>

BottomSheet组件使用问题

使用RN开发地图相关业务,需要实现类似滴滴打车底部滑动效果,所以使用了 @gorhom/bottom-sheet这个库,可以说它是十分的强大,可以满足你RN业务中95%以上的底部弹窗效果;开发过程中遇到了几个注意点记录一下,如果再有问题可以cue我或者看官方文档一起交流一下;

  • 组件必须先初始化,不能使用条件渲染,否则会出现组件不出现的情况;

  • 控制组件隐藏或者展示请使用组件提供的方法, 采用其他方式都可能出现无法展开的情况;

    展开

    bottomSheetRef.current?.snapToIndex(0);
    

    关闭

    bottomSheetRef.current?.close();
    
  • 默认隐藏通过设置属性 index={-1} 来实现;

ts中数组的一些常用函数提高效率

在项目开发中经常会遇到需要便利一个数组来判断元素是否符合条件,我们常用的方法就是对书数组使用map() 方法或者是 forEarch() 方法; 除此之外还有其他几个很好有的方法,可以方便使用,是我们的代码写的更加优雅。

  • map()forEarch() 的区别;

  • forEarch() 函数, 返回值为 void

    使数组中每个元素执行一次回调函数;会改变原来数组的值;

    let num = [7, 8, 9];
    num.forEach((item, index) => {
        return (num[index] = item * 2);
    });
    

    console.log(num)执行结果如下:

    截屏2022-01-09 下午12.11.02.png

  • map() 函数, 有返回值且返回值是一个新数组

    通过指定函数处理数组的每个元素,并返回处理后的数组;

    let num = [7, 8, 9];
    let res = num.map((item, index) => {
        return (num[index] = item * 2);
    });
    
    

    截屏2022-01-09 下午5.47.12.png

    区别总结:

    1. 能用forEach()做到的,map()同样可以。反过来也是如此。

    2. map()会分配内存空间存储新数组并返回,forEach()不会返回数据。

    3. forEach()允许callback更改原始数组的元素。map()返回新的数组。

  • every() 函数,检测数值元素的每个元素是否都符合条件

    function isBigEnough(element, index, array) { 
            return (element >= 10); 
    } 
    
    var passed = [12, 5, 8, 130, 44].every(isBigEnough); 
    console.log("Test Value : " + passed ); // false
    
  • some() 函数,检测数组元素中是否有元素符合指定条件

    在商城售后业务中判断opertion中的按钮时可以用

    const haveOpItem = detailData?.operations?.some(
        (item: { code: string; name: string }) =>
            operation.pickupTypeOp.includes(item.code)
    );
    
    
  • filter() 函数,检测数值元素,并返回符合条件所有元素的数组

    let num = [7, 8, 9];
    let result = num.filter((item ,index, array) => { 
        console.log(`item=== ${item}---array ==== ${array}` ); 
        return item === 7 
     })
    

    console.log(result) 执行结果:

    截屏2022-01-09 下午7.25.55.png

    如果没有符合元素的数组返回为空数组

    let num = [7, 8, 9];
    let result = num.filter((item ,index, array) => { 
        console.log(`item=== ${item}---array ==== ${array}` ); 
        return item === 0
    })
    

    执行结果

    截屏2022-01-09 下午7.28.11.png

redux中数据修改时机问题

使用redux时候需要在某些时机对redux数据做处理,可监听组件然后对数据做处理;

注意需要移除订阅

useEffect(() => {
        const unsubscribe = navigation.addListener('beforeRemove', () => {
            dispatch(
                actions.responseReason({
                    // @ts-ignore
                    data: []
                })
            );
        });
        return unsubscribe;
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [navigation, route]);

iOS滑动返回数据更新问题

问题:在RN项目中使用@react-navigation/native 管理多个页面时,iOS侧滑返回手势无法监听;

解决方案

  • 简单粗暴解决:在导航栏初始化阶段直接禁用滑动返回手势

     screenOptions={{
         headerShown: false,
         gestureEnabled: false
     }}
    
  • 完美解决:使用StackActions 修改导航参数

    const navigateAction = StackActions.replace(
         'Name',
         {
             param: ojb
         }
     );
     navigation.dispatch(navigateAction);
        
    

RN开发中可能会引起app crash的常见几种情况

  1. 接口数据解析一定要用可选属性 ?, 说不定哪天接口就返回null或者整个对象不返回了;

  2. 使用JSON.parse()将一个json字符串转为对象时如果为null或者undefind会 crash;所以最好是JSON.parse(data || '')

  3. 获取接口数组中某个元素时应该用可选属性;比如 detailData?.gpsList?.[0].lat;而不能使用 detailData?.gpsList[0]?.lat, 因为接口数组有可能会返回null;

  4. 条件渲染时需要对其中条件字段进行可选过滤例如:

    {detailData?.reminder?.sendBackTip && (
        <Text style={styles.sendBackTip}>
            {detailData?.reminder?.sendBackTip}
        </Text>
    )}
    
  5. 对于数组是否有值判断采用:先去数组可选值再双重去反的方式或者直接判断length > 0,例如:

    {!!expressCompanyList?.length && (...)}
    
  6. timeOut 定时器使用了一定要清楚,不清除会有性能问题导致crash

    const timer = setTimeout(() => {
       bottomSheetRef.current?.snapToIndex(0);
       clearTimeout(timer);
    }, 2000);
    

弹窗页面在安卓机型上偶尔不展示问题

  • 问题:页面会有弹出一个覆层的需求,类似查看合同或者协议;此弹窗组件是采用RN来实现;在iOS一切正常,在安卓机型上第一次可正常弹出,如果弹出过一次后,由于其他的原因调用了安卓原生的页面,再次打开弹窗后就会无效;

  • 解决方案:使用 react-native-root-siblings 库中的 <RootSiblingParent> 标签在所需要弹窗的RN页面包裹;

具体实现可以自定义一个函数判平台只针对安卓进行处理

出现此问题原因尚不明确;分析可能是因为打开原生页面对当前的主window的层级有影响

安卓手机数字展示不全问题

  • 问题:页面中身份证号码最后一位不展示;使用RN页面在小米手机MiUi 11.0系统上可能会出现文字被截取的情况

此问题定位了好久,刚开始认为是宽度不够或者是没有设置flex:0,最后找到问题可能是MiUi的字体问题导致;可参考 解决方案

  • 解决方案:对字体进行hook替换成系统默认字体

文字tag标签实现

需要实现的UI样式如图: image.png

  • 思路:在Text组件中渲染文本和 自定义的tag组件
  <Text numberOfLines={2} style={{...}}>
              {'我是标题'} 
              {<View style={{...}}>
              <Text style={{...}}>
                  {'我是标签'}
              </Text>
          </View>}
   </Text>

安卓机型渲染偏上问题

  • 使用 transform 属性修改渲染的开始位置

    style: {
        transform: [{ translateY: Platform.OS === 'android' ? 3 : 0 }],
    }
    

RN调用原生组件报错

  • 问题:原生封装组件导出给NeactNative使用步骤,官方文档有说明在NeactNative文件中原生导出组件直接使用,不能在用NeactNative的标签包裹否则直接报错

  • 错误代码

    return (
                <View>
                    <RNImageView
                       {...this.props}
                    />
                </View>
            );
    
  • 正确代码

    render() {
            return (
                <RNImageView
                    {...this.props}
                />
            );
        }