在开发过程中遇到的问题总结
一、 Unable to resolve module react-native-gesture-handler from node_modules\@react-navigation\native\lib\module\Scrollables.js: react-native-gesture-handler could not be found within the project.
npm install --save react-native-gesture-handler
react-native link react-native-gesture-handler(16+版本不需要)
二、createStackNavigator() has been move to react-navigation-stack
由于React Navigation 更新,createBottomTabNavigator,createStackNavigator无法继续在react-navigation直接引入,而是需要在新的包react-navigation-tabs和react-navigation-stack里引入,基本语法暂未发现变化;
npm install --save react-native-stack
三、can not resolve module "react-native-screens"
npm install --save react-native-screens
四、Execution failed for task ':app:processDebugResources'.
进入android目录执行
./gradlew clean
五、The navigation props is missing for you must setup you app
render() {
const Tab = createAppContainer(this._tabNavigator());
return <Tab />;
}
六、react-native-vector-icons图标不正常显示
安卓平台下:在android/app/build.grade文件的最后加上并重启即可
project.ext.vectoricons = [
iconFontNames: [ 'MaterialIcons.ttf', 'EvilIcons.ttf' ] // 你想要复制的字体文件的名字
]
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
七、在rn最热页面跳转到详情页中 onPress随着render自动执行
原因:在RN的页面代码中,花括号 {} 有取对象值的意思在內,而方法也是对象的一种,因此,这里并不单单是为onPress指定属性值那么简单,在赋值的同时还自动调用了一次该响应方法。 使用箭头函数为onPress定义响应函数,箭头函数內调用对应的响应函数即可。
onPress={()=>{
}}
八、禁用黄色警告
console.disableYellowBox=true;
九、dispatch导致重新render
在集成redux中通过Button按钮点击触发dispatch改变state实现改变主题色的效果,但是由于state改变 注入state的组件重新render了 导致会产生还原的一个效果这时:可以将组件保存在变量中 下次render的时候判断是否生成过,生成过直接返回
_tabNavigator() {
if(this.Tabs){
return this.Tabs;
}
const {PopularPage,MyPage,TrendingPage,FavouritePage}=TABS;
const tabs={PopularPage,MyPage,TrendingPage,FavouritePage};
return this.Tabs=createAppContainer(createBottomTabNavigator(tabs,{
tabBarComponent:props=>{
return <TabBarComponent
theme={this.props.theme}
{...props}
/>
}
}))
}
render() {
const Tab = createAppContainer(this._tabNavigator());
return <Tab />;
}
十、自定义redux中间件检测action的变化(实用)
//action是项目中触发的action
//store.getState()可以实时查看路由的变化
const logger=store=>next=>action=>{
if(typeof action==="function"){
console.log("dispatch is a function")
}else{
console.log("dispatching",action);
const result=next(action)
console.log("nextState",store.getState())
}
};
十一、处理redux中物理返回键返回上一页问题
在rn中 返回键会返回到主菜单中 所以需要一些操作
import {BackHandler} from 'react-native';
import {NavigationActions} from 'react-navigation';
componentDidMount(){
BackHandler.addEventListener("handwareBackPress",this.onBackPress);//物理返回键的监听
}
componentWillUnmount(){
BackHandler.removeEventListener("handwareBackPress",this.onBackPress);
}
/**
* 处理Android中的物理返回键
*/
onBackPress=()=>{
const {dispatch,nav}=this.props;
if(nav.routes[1].index===0){
//nav.routes[1]说明是RootNavigator中的MainNavigation如果下标是0不处理
//为0表示路由导航页面已经没有页面可以退了
return false;
}
//返回
dispatch(NavigationActions.back());
return true;
}
十二、离线缓存框架的搭建
即为了更好的用户体验 用户在手机无网络时也可以查看到数据
import { AsyncStorage } from 'react-native';
export default class DataStore{
/**
* 获取数据 优先获取本地数据 如果本地数据过期获取远程数据
* @param {*} url
* @param {*} data
* @param {*} callback
*/
fetchData(url){
return new Promise((resolve,reject)=>{
this.fetchLocalData(url).then(wrapData=>{
if(wrapData&&DataStore.checkTimestampValid(wrapData.timestamp)){
resolve(wrapData)
}else{
console.log(DataStore.checkTimestampValid(wrapData.timestamp))
this.fetchNetData(url).then(data=>{
resolve(this._warpData(data));
}).catch((error)=>{
reject(error);
})
}
}).catch(error=>{
this.fetchNetData(url).then(data=>{
resolve(this._warpData(data));
}).catch(error=>{
reject(error);
})
})
})
}
//保存数据
saveData(url,data,callback){
if(!data ||!url) return;
AsyncStorage.setItem(url,JSON.stringify(this._warpData(data),callback))
}
_warpData(data){
return {data:data,timestamp:new Date().getTime()}
}
/**
* 获取本地数据
*/
fetchLocalData(url){
return new Promise((resolve,reject)=>{
AsyncStorage.getItem(url,(error,result)=>{
if(!error){
try{
resolve(JSON.parse(result));
}catch(e){
reject(e);
console.log(e);
}
}else{
reject(error);
console.error(error);
}
})
})
}
/**
* 网络获取数据
* @param {}} timestamp
*/
fetchNetData(url){
return new Promise((resolve,reject)=>{
fetch(url)
.then(response=>{
if(response.ok){
return response.json();
}
throw new Error("network response was not ok")
})
.then(responseData=>{
this.saveData(url,responseData)
resolve(responseData)
})
.catch(error=>{
reject(error);
})
})
}
/**
* 检查timestamp是否在有效期内
*/
static checkTimestampValid(timestamp){
const currentDate=new Date();
const targetDate=new Date();
targetDate.setTime(timestamp);
if(currentDate.getMonth()!==targetDate.getMonth()) return false;
if(currentDate.getDate()!==targetDate.getDate()) return false;
if(currentDate.getHours()-targetDate.getHours()>4) return false;
return true;
}
}
其中fetchData函数是框架的核心函数,意思是请求数据,先请求本地缓存数据 看是否有数据并且检查过期时间 如果超过过期时间 则重新请求。
十三、如何动态设置redux的key
switch (action.type) {
case Types.LOADING_POPULAR_SUCCESS:
return {
...state,
[action.storeName]: {
...[action.storeName],
item: action.items,
isLoading: false
},
}
case Types.POPULAR_REFRESH:
return {
...state,
[action.storeName]: {
...[action.storeName],
isLoading: true
},
}
case Types.LOAD_POPULAR_FAIL:
return {
...state,
[action.storeName]: {
...[action.storeName],
isLoading: false
},
}
default:
return state;
}
十四、ViewPropsTypes报错
由于不渲染问题造成的问题
可以借助rn的一个重要api(DeviceEventEmitter)
import { DeviceEventEmitter } from 'react-native';
function click(){//在事件触发时分发事件
DeviceEventEmitter.emit(EVENT_TYPE_TIME_SPAN_CHANGE,tab);
}
componentDidMount(){
this.timeSpanChangeListener=DeviceEventEmitter.addListener(EVENT_TYPE_TIME_SPAN_CHANGE,(timeSpan)=>{
console.log("change time")
})
}
componentWillUnmount(){
if(this.timeSpanChangeListener){
this.timeSpanChangeListener.removeListener();
}
}