react-native

功能

定位

react-native-amap-geolocation

高德地图定位模块

hook封装

// hook
import { useState, useEffect, useCallback } from 'react';
import { Platform } from 'react-native';
import { Geolocation, setLocatingWithReGeocode, stop } from 'react-native-amap-geolocation';
import { check, request, PERMISSIONS, RESULTS } from 'react-native-permissions';
import { Toast } from '@/components';// 吐司组件
const isAndroid = Platform.OS === 'android';
const permissionType =
Platform.OS === 'ios'
? PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION;
function useAmapLocation(initLocation) {
const [location, setLocation] = useState(initLocation);
const [err, setErr] = useState();
useEffect(() => {
setTimeout(() => {
checkPermissions();
}, 1000);
return () => {
stop();
};
}, []);
const handleLocationSuccess = ({ location: _location }) => {
if (_location) {
setLocation(_location);
}
};
const handleLocationError = (e) => {
setErr({ message: '', e });
};
const getGeolocation = async () => {
if (!isAndroid) {
setLocatingWithReGeocode(true);
}
Geolocation.getCurrentPosition(handleLocationSuccess, handleLocationError);
};
const checkPermissions = useCallback(() => {
check(permissionType)
.then((result) => {
switch (result) {
case RESULTS.UNAVAILABLE:
Toast.showError('当前设备没有位置服务');
break;
case RESULTS.DENIED:
requestPermissions();
break;
case RESULTS.GRANTED:
getGeolocation();
break;
case RESULTS.BLOCKED:
Toast.showError('您设定永不授权,请自行前往设置开启');
break;
default:
break;
}
})
.catch(() => {});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const requestPermissions = () => {
request(permissionType)
.then((result) => {
if (result === RESULTS.GRANTED) {
getGeolocation();
} else {
setErr({ message: '没有定位权限' });
}
})
.catch(() => {});
};
return { location, err };
}
export default useAmapLocation;

地图

react-native-amap3d

高德地图组件

渐变文字实现

使用的库

  1. @react-native-community/masked-view

  2. react-native-linear-gradient

组件封装

import React from 'react';
import { StyleSheet } from 'react-native';
import MaskedView from '@react-native-community/masked-view';
import LinearGradient from 'react-native-linear-gradient';
function GradientText({ children, style, ...restProps }) {
return (
<MaskedView style={style} maskElement={children}>
{/* Shows behind the mask, you can put anything here, such as an image */}
<LinearGradient
start={start}
end={end}
colors={colors}
style={[StyleSheet.absoluteFill]}
{...restProps}
/>
</MaskedView>
);
}

使用

<GradientText colors={['black','white]}>
<Text>渐变文字</Text>
</GradientText>

三角形组件

import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';
function getBorderStyles({ direction, width, height, color }) {
if (direction === 'up') {
return {
borderTopWidth: 0,
borderRightWidth: width / 2.0,
borderBottomWidth: height,
borderLeftWidth: width / 2.0,
borderTopColor: 'transparent',
borderRightColor: 'transparent',
borderBottomColor: color,
borderLeftColor: 'transparent',
};
} else if (direction === 'right') {
return {
borderTopWidth: height / 2.0,
borderRightWidth: 0,
borderBottomWidth: height / 2.0,
borderLeftWidth: width,
borderTopColor: 'transparent',
borderRightColor: 'transparent',
borderBottomColor: 'transparent',
borderLeftColor: color,
};
} else if (direction === 'down') {
return {
borderTopWidth: height,
borderRightWidth: width / 2.0,
borderBottomWidth: 0,
borderLeftWidth: width / 2.0,
borderTopColor: color,
borderRightColor: 'transparent',
borderBottomColor: 'transparent',
borderLeftColor: 'transparent',
};
} else if (direction === 'left') {
return {
borderTopWidth: height / 2.0,
borderRightWidth: width,
borderBottomWidth: height / 2.0,
borderLeftWidth: 0,
borderTopColor: 'transparent',
borderRightColor: color,
borderBottomColor: 'transparent',
borderLeftColor: 'transparent',
};
} else if (direction === 'up-left') {
return {
borderTopWidth: height,
borderRightWidth: width,
borderBottomWidth: 0,
borderLeftWidth: 0,
borderTopColor: color,
borderRightColor: 'transparent',
borderBottomColor: 'transparent',
borderLeftColor: 'transparent',
};
} else if (direction === 'up-right') {
return {
borderTopWidth: 0,
borderRightWidth: width,
borderBottomWidth: height,
borderLeftWidth: 0,
borderTopColor: 'transparent',
borderRightColor: color,
borderBottomColor: 'transparent',
borderLeftColor: 'transparent',
};
} else if (direction === 'down-left') {
return {
borderTopWidth: height,
borderRightWidth: 0,
borderBottomWidth: 0,
borderLeftWidth: width,
borderTopColor: 'transparent',
borderRightColor: 'transparent',
borderBottomColor: 'transparent',
borderLeftColor: color,
};
} else if (direction === 'down-right') {
return {
borderTopWidth: 0,
borderRightWidth: 0,
borderBottomWidth: height,
borderLeftWidth: width,
borderTopColor: 'transparent',
borderRightColor: 'transparent',
borderBottomColor: color,
borderLeftColor: 'transparent',
};
} else {
console.error(
'Triangle.js wrong direction. ' +
direction +
' is invalid. Must be one of: ' +
['up', 'right', 'down', 'left', 'up-right', 'up-left', 'down-right', 'down-left']
);
return {};
}
}
function Triangle({ direction, width, height, color, style }) {
const borderStyles = getBorderStyles({ direction, width, height, color })
return <View style={[{ width:0,height:0,backgroundColor:'transparent',borderStyle:'solid' }, borderStyles, style]} />;
}
Triangle.defaultProps = {
width: 30,
height: 30,
color: 'black',
direction: 'up',
};
Triangle.propTypes = {
width: PropTypes.number,
height: PropTypes.number,
color: PropTypes.string,
direction: PropTypes.oneOf([
'up',
'down',
'left',
'right',
'up-left',
'up-right',
'down-left',
'down-right',
]),
};
export default Triangle;

Aliyunoss hook

hook

import { useState, useEffect, useCallback } from 'react'
import RNAliyunOSS from 'aliyun-oss-react-native'
import { Toast } from '@/components'
const getToken = () => {
return { stsToken: '', accessKeyId: '', accessKeySecret: '', endPointPath: '' }
} // 获取token的API
const FILE_PREFIX = 'test' // 目录
function useAliyunOss() {
const [ossToken, setOssToken] = useState()
const [instance, setInstance] = useState()
useEffect(() => {
fetchToken()
}, [])
useEffect(() => {
if (ossToken) {
initAliOss()
}
}, [ossToken, initAliOss])
const fetchToken = () => {
return getToken().then((res) => {
setOssToken(res)
return res
})
}
const initAliOss = useCallback(async () => {
const { stsToken, accessKeyId, accessKeySecret, endPointPath } = ossToken || {}
try {
const configuration = {
maxRetryCount: 3,
timeoutIntervalForRequest: 30,
timeoutIntervalForResource: 24 * 60 * 60,
}
RNAliyunOSS.enableDevMode()
RNAliyunOSS.initWithSecurityToken(stsToken, accessKeyId, accessKeySecret, endPointPath, configuration)
setInstance(RNAliyunOSS)
} catch (error) {
console.log(error)
}
}, [ossToken])
const upload = useCallback(
({ path }) => {
if (!instance) {
Toast.showError('初始化上传组件失败,请稍后重试')
fetchToken()
return Promise.reject()
}
const { bucket, endpoint } = ossToken || {}
const fileName = path.split(/\#|\?/)[0].split('/').pop().trim()
const filePath = `file://${path}`
const objectkey = `${FILE_PREFIX}/${fileName}`
return instance.asyncUpload(bucket, objectkey, filePath).then((res) => {
const newPath = `${endpoint}/${objectkey}`
return newPath
})
},
[instance, ossToken]
)
return { AliyunOSS: instance, ossToken, fetchToken, upload }
}
export default useAliyunOss

使用

function Example() {
const { upload } = useAliyunOss()
const updateImage = async () => {
try {
const imagePickerRes = await ImagePicker.openPicker({
width: 400,
height: 400,
cropping: true,
cropperToolbarColor: 'white',
cropperChooseText: '选择',
cropperCancelText: '取消',
loadingLabelText: '加载中',
})
const { path } = imagePickerRes
const uploadRes = await upload({ path })
console.log(uploadRes)
} catch (error) {
console.log(error)
}
}
return null
}

H5的通信

const RnMapArray = [
'navigateTo',
'navigateBack',
'switchTab',
'reLaunch',
'redirectTo',
'postMessage',
'setTitle',
'setShare',
];
(function FuncMap(target) {
if (!target) {
return null;
}
var Funcobj = {}; // RN映射方法
RnMapArray.forEach(function(func) {
Funcobj[func] = function(...payload) {
const params = {
command: func,
payload: { ...payload },
};
target.ReactNativeWebView.postMessage(JSON.stringify(params));
};
}); // 实例方法
Funcobj.getEnv = function(callback) {
if (typeof callback !== 'function') {
return;
}
var isRn = localStorage.getItem('isRN');
var data = {
rn: isRn,
};
callback(data);
}; // 挂载到目标上
target.RN = Funcobj;
})(window);

debug

编译失败

版本冲突

  • 根据错误信息定位哪个包有问题,google搜索错误信息关键词,一般会定位到github包下面的issue,因为你犯的错误,很可能别人也碰到了,正好大家在讨论,而且可能还有人给出了解决方案

App架构设计

环境处理

测试环境,线上环境

常用hook封装

工具类函数

样式方案选择scss

状态管理选用redux

路由使用react-navigation

常量定义

公共组件库

功能组件,UI组件

公共图片资源

请求方法的封装