美文网首页
react-navigation的screen参数使用高阶组件时

react-navigation的screen参数使用高阶组件时

作者: 黑哥_2c57 | 来源:发表于2019-05-23 16:43 被阅读0次

场景:

react-native react-navigation @react-native-community/netinfo

需求:

假设我的底部导航有三个页面,每个页面需要在进入前都检查当前是否联网,没有联网的情况下,显示另一个页面,只有在有网络的情况下再进入响应的页面。


image.png

实现一:

先写公共的网络跑丢的页面,然后在每个页面进行逻辑判断, 不同情况显示不同页面,这个当然可以实现,但是逻辑判断那部分每个页面都写一次,就重复了,这个就不写代码了,更好的方式是使用高阶组件修饰,请看实现二。

实现二:

先写一个WithNoNet的高阶组件, 然后在每个页面中使用WithNoNet修饰一下,实现将这部分判断逻辑抽离出来,简洁优雅高效。

//WithNoNet高阶组件
import React from 'react'
import NetInfo from "@react-native-community/netinfo";
import NoNetwork from '../common/NoNetwork'

export default WrappedComponent => {
    return class extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                isConnected: false,
                hasCheckedNetwork: false, //为了解决执行网络检查时,NoNetwork页面一闪而过的现象
            }
        }

        async componentDidMount(): void {
            await this.checkNetwork()
        }

        checkNetwork = async () => {
            try {
                let netInfo = await NetInfo.fetch()
                if (netInfo.isConnected) {
                    this.setState({
                        isConnected: true,
                        hasCheckedNetwork: true,
                    })
                } else {
                    this.setState({
                        hasCheckedNetwork: true,
                    })
                }
            } catch (e) {
                console.log(e)
            }
        }

        render() {
            const {isConnected, hasCheckedNetwork} = this.state
            if (isConnected) {
                return <WrappedComponent />
            } else {
                if (hasCheckedNetwork) {
                    return <NoNetwork checkNetwork={this.checkNetwork}/>
                } else {
                    return null
                }
            }
        }
    }
}

Home主页使用WithNoNet修饰

//Home主页使用WithNoNet修饰
import React from 'react'
import { View,Text} from 'react-native'
import WithNoNet from '../WithNoNet'
class Home extends React.Component {
    componentDidMount(){
          console.log(this.props.navigation)    
    }
    render() {
        return (
            <View>
            <Text> This is home </Text>
            </View>
        )
    }
}
export default WithNoNet(Home)

现在开始进入本文主题

这样修饰了之后,一看没啥问题,但是我一运行就出问题了, 因为Home组件的props中的navigation成了undefined,检查我的底部导航组件

import React from 'react'
import {createBottomTabNavigator, createAppContainer} from 'react-navigation'
import Base from '../page/Base'
import My from '../page/My'
import Ionicons from 'react-native-vector-icons/Ionicons'
import Home from '../page/Home/Home'
import Alert from '../page/Alert'
import {ACTIVATE_COLOR} from "../config/constant";
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5'
const bottomNavigator = createBottomTabNavigator({
        Home: {
            screen:Home,
            navigationOptions: {
                tabBarLabel: "首页",
                tabBarIcon: ({tintColor, focused}) =>
                    <Ionicons
                        name={'md-home'}
                        size={20}
                        color={tintColor}
                    />
            }
        },
        Alert: {
            screen:Alert,
            navigationOptions: {
                tabBarLabel: "告警",
                tabBarIcon: ({tintColor, focused}) =>
                    <MaterialCommunityIcons
                        name={'alert-decagram'}
                        size={20}
                        color={tintColor}
                    />
            }
        },
      
        My: {
            screen: My,
            navigationOptions: {
                tabBarLabel: "我的",
                tabBarIcon: ({tintColor, focused}) =>
                    <FontAwesome5
                        name={'user-circle'}
                        size={20}
                        color={tintColor}
                    />
            }
        },
    },
    {
        tabBarOptions: {
            activeTintColor: ACTIVATE_COLOR,
            labelStyle: {
                fontSize: 13,
            },
        }
    }
)

发现很有可能是因为Home进行了WithNoNet组件包裹,导致navigation组件传递不过去了,怎么办呢?
先google一把,然并卵,没找到答案,只能自己啃了。。。
首先我觉得应该在screen参数上下功夫,于是去react-navigation官网看createStackNavigation的 screen相关的东西,然而除了已知的能传一个组件(就像现在的做法)作为参数,也没有发现更多。
我看代码中 tabBarIcon可以是一个函数返回一个组件, 猜猜screen行不行呢?

tabBarIcon: ({tintColor, focused}) =>
                    <FontAwesome5
                        name={'user-circle'}
                        size={20}
                        color={tintColor}
                    />

于是试了一把,改为

Home: {
            screen: ({navigation}) => <Home navigation={navigation}/>,
            navigationOptions: {
                tabBarLabel: "首页",
                tabBarIcon: ({tintColor, focused}) =>
                    <Ionicons
                        name={'md-home'}
                        size={20}
                        color={tintColor}
                    />
            }
        },

然后我在WithNoNet中componentDidMount中打印this.props.navigation, 发现真打印出来了,那么这个问题就好办了,直接将navigation传递给子组件就行了。将WithNoNet改为如下

//WithNoNet高阶组件
import React from 'react'
import NetInfo from "@react-native-community/netinfo";
import NoNetwork from '../common/NoNetwork'

export default WrappedComponent => {
    return class extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                isConnected: false,
                hasCheckedNetwork: false, //为了解决执行网络检查时,NoNetwork页面一闪而过的现象
            }
        }

        async componentDidMount(): void {
            await this.checkNetwork()
        }

        checkNetwork = async () => {
            try {
                let netInfo = await NetInfo.fetch()
                if (netInfo.isConnected) {
                    this.setState({
                        isConnected: true,
                        hasCheckedNetwork: true,
                    })
                } else {
                    this.setState({
                        hasCheckedNetwork: true,
                    })
                }
            } catch (e) {
                console.log(e)
            }
        }

        render() {
            const {isConnected, hasCheckedNetwork} = this.state
            const {navigation} = this.props  //获取navigation并传递给WrappedComponent

            if (isConnected) {
                return <WrappedComponent navigation={navigation}/>
            } else {
                if (hasCheckedNetwork) {
                    return <NoNetwork checkNetwork={this.checkNetwork}/>
                } else {
                    return null
                }
            }
        }
    }
}

然后在Alert,my页面都引入WithNoNet组件,导出是进行包裹, 再将底部导航的所有screen配置为如下:

const bottomNavigator = createBottomTabNavigator({
        Home: {
            screen: ({navigation}) => <Home navigation={navigation}/>,
            navigationOptions: {
                tabBarLabel: "首页",
                tabBarIcon: ({tintColor, focused}) =>
                    <Ionicons
                        name={'md-home'}
                        size={20}
                        color={tintColor}
                    />
            }
        },
        Alert: {
            screen: ({navigation}) => <Alert navigation={navigation}/>,
            navigationOptions: {
                tabBarLabel: "告警",
                tabBarIcon: ({tintColor, focused}) =>
                    <MaterialCommunityIcons
                        name={'alert-decagram'}
                        size={20}
                        color={tintColor}
                    />
            }
        },
      
        My: {
            screen: ({navigation}) => <My navigation={navigation}/>,
            navigationOptions: {
                tabBarLabel: "我的",
                tabBarIcon: ({tintColor, focused}) =>
                    <FontAwesome5
                        name={'user-circle'}
                        size={20}
                        color={tintColor}
                    />
            }
        },
    },
    {
        tabBarOptions: {
            activeTintColor: ACTIVATE_COLOR,
            labelStyle: {
                fontSize: 13,
            },
        }
    }
)

同时附上NoNetwork页面的代码

import React from 'react'
import {TouchableOpacity, Text, StyleSheet, Dimensions, Image} from 'react-native'

const errorImg = require('../res/icons/color/noNetwork.png')
const {height} = Dimensions.get('window')
export default class NoNetwork extends React.PureComponent {
    render() {
        return <TouchableOpacity
            style={styles.wrapper}
            onPress={this.props.checkNetwork}
        >
            <Image
                source={errorImg}
                style={styles.img}
            />
            <Text>网络跑丢啦!!</Text>
            <Text>轻触重试</Text>
        </TouchableOpacity>
    }
}
const styles = StyleSheet.create({
    wrapper: {
        height: height - 80,
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
    img: {
        width: 40,
        height: 40,
    },
})

大功告成了,哈哈哈,解决了这个问题,让我对react的高阶组件理解更深刻了,也更喜欢高阶组件了。
同时希望能帮助到有相同问题的同学!!!

相关文章

  • react-navigation的screen参数使用高阶组件时

    场景: react-native react-navigation @react-native-community...

  • React-native 之 react-navigation

    react-navigation导航栏组件 具体参数 使用方法 1:导入组件npm install react-n...

  • react小书学习mark

    1、高阶组件是一个函数,接受一个组件作为参数,返回一个新的组件。新的组件使用传入的组件作为子组件。1.1、高阶组件...

  • React高阶组件HOC

    高阶组件本质是函数,参数是 组件1 返回组件2,高阶组件是为了复用通用逻辑高阶组件eg:import React,...

  • React 高阶组件

    高阶函数 函数可以作为参数被传递 函数可以作为返回值输出 高阶组件 高阶组件接受一个组件作为参数,并返回一个新组件...

  • React高阶组件

    高阶组件定义:高阶组件就是一个函数,该函数接受一个组件作为参数,并返回一个新的组件高阶组件的作用:封装并抽离组件中...

  • React_高阶组件的使用

    1.什么是高阶组件? 官方的定义:高阶组件是参数为组件,返回值为新组件的函数; 高阶函数的维基百科定义:至少满足以...

  • react 高阶组件的应用

    一、什么是高阶组件 高阶组件其实就是一个函数,他会接收一个组件作为参数并返回一个经过改造后的组件 二、高阶组件的实...

  • 高阶组件

    higher-order-component (高阶组件HOC)类似于高阶函数,它接受一个React组件作为参数,...

  • 高阶函数与高阶组件

    高阶函数:高阶函数只要满足参数或返回值为函数就可以成为高阶函数,而非一定要同时满足才成立。 高阶组件:高阶组件是以...

网友评论

      本文标题:react-navigation的screen参数使用高阶组件时

      本文链接:https://www.haomeiwen.com/subject/cskbzqtx.html