如果我位于RootPage上,如何访问this.props.navigation?

时间:2019-04-11 07:41:30

标签: react-native react-navigation

我需要将此this.props.navigation传递给一个辅助函数。但是,我目前正坐在根页面上,该页面最初创建了stackNavigator。到目前为止,我已经尝试从react-navigation导入Navigator,NavigatorActions和withNavigation,然后将其作为参数发送到我的辅助函数中,但是我一直收到错误消息:无法读取未定义的属性“ state”。

以下是与我相关的RootPage代码:

    /**
 * RootPage has the Navigator. So it controls navigation.
 */
import React, { Component } from 'react';
import {
    Platform,
    BackHandler,
    View,
    Animated,
    StyleSheet,
    Image,
    TouchableWithoutFeedback,
    TouchableOpacity,
    Alert
} from 'react-native';
import { connect } from 'react-redux';
import { BoxShadow } from 'react-native-shadow';
import { NavigationActions } from 'react-navigation';
import { vsprintf } from 'sprintf-js';
import RootNavigator from './RootNavigator';


//Test Component
import TestPageFactory from '../TestPage/TestPageFactory';

// Components
import XXBluetoothManager, { XXBluetoothEventEmitter } from '../../nativeComponents/XXBluetooth/XXBluetooth';
import XXText from '../../components/XXText/XXRobotoText';
import XXSyncXXerlay from '../../components/XXSyncXXerlay/XXSyncXXerlay';
// Actions
import { logout } from '../../actions/user';
import { closeSyncModal, toggleRootMenu, openRootMenu, closeRootMenu } from '../../actions/page';
// Utils
import { LAYOUTINFO } from '../../utils/layoutinfo';
import { generateElevationStyle } from '../../utils/util';
import { NavUtils } from '../../utils/navutils';
import { StatusBarManager } from '../../utils/statusbarmanager';
// Config
import { DEVICEINFO } from '../../config';
// Localization
import I18n from '../../localization/i18n';
import { aDeviceHasBeenConnectedFunc } from '../../actions/device';
// Constants
const DEFAULT_PROFILE_IMAGE = require('../../images/profile-image/user.png');
const HEIGHT_RATIO = DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 0.5 : (DEVICEINFO.SCREEN_HEIGHT >= 667 ? (DEVICEINFO.SCREEN_HEIGHT / 667) : 0.7);

class RootPage extends Component {
    static getDerivedStateFromProps(nextProps, prevState) {
        let shouldLoadingBeVisible = nextProps.pageStatus && nextProps.pageStatus.isUpdateRequested ? true : false;
        if (!nextProps.profile && shouldLoadingBeVisible === prevState.loadingVisible) {
            return null;
        }
        return {
            profileImage: nextProps.profile && nextProps.profile.profileImage ?
                { uri: nextProps.profile.profileImage } : DEFAULT_PROFILE_IMAGE,
            profileName: nextProps.profile && nextProps.profile.profileName ? nextProps.profile.profileName : '',
            loadingVisible: shouldLoadingBeVisible,
        };
    }
    constructor(props) {
        super(props);
        this.routeStatusBarStyle = 'dark-content';
        this.state = {
            animatedPosition: new Animated.ValueXY(0, 0),
            profileImage: DEFAULT_PROFILE_IMAGE,
            profileName: '',
            deviceAddress: undefined,
            isMenuVisible: false,
            loggingOut: false,
            device: undefined,

        };
    }
    componentDidMount() {
        if (Platform.OS === 'android') {
            this.initAndroidHardwareBackEvent();
        }
        // this.initializeBluetooth();
    }
    componentWillUnmount() {
        this.destroyBluetooth();
    }
    componentDidUpdate(prevProps, prevState) {
        if (this.state.loggingOut) {
            if (this.props.signinStatus && !this.props.signinStatus.isLoginSuccess) {
                this.setState({ loggingOut: false }, () => {
                    this.onPressMenu('EntryPage');
                });
            }
        }
        if (this.props.pageStatus.isMenuVisible != null && prevState.isMenuVisible !== this.props.pageStatus.isMenuVisible) {
            this.setState({ isMenuVisible: this.props.pageStatus.isMenuVisible }, () => {
                this.onUpdateMenu(this.props.pageStatus.isMenuVisible);
            });
        }
        // console.log('what are the prev state here? ", ', prevState)
        /* 
        NOTE: We need to know when an item has been connected, if an item has not been connected, we should
        make the hearing test available
        */
    }
    render() {
        return (
            <View style={styles.rootView}>
                {this.renderRootMenu()}
                <Animated.View style={[styles.animatedView, { left: this.state.animatedPosition.x, top: this.state.animatedPosition.y }]}>
                    {this.renderXXerlay()}
                    {this.renderNavigator()}
                </Animated.View>
                {this.renderSyncXXerlay()}
            </View>
        );
    }
    updateStatusBarStyle(pageId) {
        let newStatusBarStyle = 'dark-content';
        if (pageId === 'EntryPage') {
            newStatusBarStyle = 'light-content';
        }
        if (newStatusBarStyle !== this.routeStatusBarStyle) {
            this.routeStatusBarStyle = newStatusBarStyle;
            StatusBarManager.setStyle(newStatusBarStyle, false)
        }
    }
    renderRootMenu() {
        return (
            <View style={styles.menuView}>
                {this.renderMenuTopArea()}
                {this.renderMenuBottomArea()}
            </View>
        )
    }
    renderMenuTopArea() {
        if (DEVICEINFO.IS_ANDROID && (Platform.Version === 19 || Platform.Version === 20)) {
            return this.renderMenuTopAreaKitKat();
        }
        return this.renderMenuTopAreaDefault();
    }
    renderMenuTopAreaDefault() {
        return (
            <View style={[styles.menuTopArea, generateElevationStyle(1.5)]}>
                {this.renderProfileImage()}
            </View>
        )
    }
    renderMenuTopAreaKitKat() {
        let shadowOptions = {
            width: DEVICEINFO.SCREEN_WIDTH,
            height: (DEVICEINFO.SCREEN_HEIGHT * 0.35) + 2,
            color: '#000',
            border: 2,
            opacity: 0.05,
            radius: 1,
            y: -2.5,
        };
        return (
            <BoxShadow setting={shadowOptions}>
                <View style={styles.menuTopArea}>
                    {this.renderProfileImage()}
                </View>
            </BoxShadow>
        )
    }
    renderMenuBottomArea() {
        return (
            <View style={styles.menuBottomArea}>
                {this.renderMenuContents()}
            </View>
        )
    }
    renderMenuContents() {
        const menuData = this.generateMenuData();
        let renderOutput = [];
        for (let i = 0, len = menuData.length; i < len; i++) {

            if (this.state.deviceAddress && menuData[i].onlyNotConnected) {
                continue;
            }
            let extraStyle = {};
            if (i === 0) {
                let extraStyleMarginTop = DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 16 : 26;
                extraStyle['marginTop'] = extraStyleMarginTop * LAYOUTINFO.DESIGN_HEIGHT_RATIO;
            }
            renderOutput.push(
                <TouchableOpacity
                    key={menuData[i].text}
                    activeOpacity={0.8}
                    underlayColor='transparent'
                    onPress={() => { menuData[i].onPressMenu() }}
                    style={[styles.menuButtonTouch, extraStyle]}>
                    <View style={styles.menuButtonView}>
                        <Image
                            source={menuData[i].icon}
                            style={[styles.menuIcon]} />
                        <XXText style={[styles.menuText]}>{menuData[i].text}</XXText>
                    </View>
                </TouchableOpacity>
            )
        }
        return renderOutput;
    }
    generateMenuData() {
        return [
            this.generateMenuItem(I18n.t('home'), require('../../images/menu-home.png'), 'HomePage'),
            this.generateMenuItem(I18n.t('tutorial'), require('../../images/menu-tutorial.png'), 'SelectTutorialPage'),
            this.generateMenuItem(I18n.t('item_list'), require('../../images/menu-add-item.png'), 'itemListPage'),
            this.generateMenuItem(I18n.t('report'), require('../../images/menu-report.png'), 'ReportDetailPage'),
            this.generateTestPageOnly(I18n.t('hearing_test'), require('../../images/menu-demotest.png')),
            this.generateMenuItem(I18n.t('equalizer'), require('../../images/menu-sound.png'), 'SoundPage'),
            this.generateMenuItem(I18n.t('support'), require('../../images/menu-support.png'), 'SupportPage'),
            this.generateMenuItem(I18n.t('account_settings'), require('../../images/menu-settings.png'), 'SettingsPage'),
            {
                text: I18n.t('logout'),
                icon: require('../../images/menu-logout.png'),
                onPressMenu: () => {
                    Alert.alert(
                        I18n.t('item'),
                        I18n.t('logout_confirmation'),
                        [
                            { text: I18n.t('cancel'), onPress: () => { } },
                            { text: I18n.t('logout'), onPress: () => { this.onPressLogout() } }
                        ]
                    )
                }
            },
        ];
    }

    generateTestPageOnly(label, icon) {
        let deviceAddress;
        let versionData;
        // console.log('what is the props here: ', this.props.devices)
        function loopThruObject(objectOfDevices) {

            for (let [key, value] of Object.entries(objectOfDevices)) {
                for (let [newKey, newValue] of Object.entries(value)) {
                    if (newKey === 'macAddress') {
                        deviceAddress = newValue;
                    }
                    if (newKey === 'version')
                        versionData = newValue
                }
            }

            return;
        }
        loopThruObject(this.props.devices)
        let currentDevice = this.props.devices[deviceAddress];

        let newParams = {
            navIndex: 1,
            device: currentDevice
        };
        if (this.props.aDeviceHasBeenConnected === true) {
            return {
                text: label,
                icon: icon,
                onPressMenu: () => {
                    let testPageIdentifier = TestPageFactory.getIdentifier({ isDemo: false, versionData: versionData });
                    console.log('what is the testPage identifier: ', this.props.navigation)
                    // NavUtils.push(NavigationActions, testPageIdentifier, { device: currentDevice });
                    NavigationActions.dispatch({ type: 'Navigation/NAVIGATE', routeName: 'FittingTestPage', params: newParams })

                }
            }
        }
        if (this.props.aDeviceHasBeenConnected === false) {
            return {
                text: 'N/A',
                icon: icon,
                onPressMenu: () => {


                }
            }

        }
    }
    generateMenuItem(label, icon, onPressId, onlyNotConnected = false) {
        return {
            text: label,
            icon: icon,
            onPressMenu: () => {
                this.onPressMenu(onPressId);
            },
            onlyNotConnected
        }
    }
    renderProfileImage() {
        imageSource = this.state.profileImage;
        let deviceCount = Object.keys(this.props.devices).length;
        let deviceConnectionString = this.generateConnectedString(deviceCount);
        return (
            <View style={styles.profileImageSubContainer}>
                <Image
                    key={this.state.profileImage.uri}
                    source={imageSource}
                    style={styles.profileImage} />
                {/* <XXText style={[styles.profileText]} fontWeight='Regular'>{this.state.profileName}</XXText> */}
                <XXText style={[styles.deviceText]} fontWeight={'Light'}>{deviceConnectionString}</XXText>
            </View>
        )
    }
    generateConnectedString(deviceCount) {
        let deviceConnectionString;
        if (deviceCount === 1) {
            deviceConnectionString = vsprintf(I18n.t('one_item_connected_format_str'), deviceCount.toString());
        }
        else {
            deviceConnectionString = vsprintf(I18n.t('items_connected_format_str'), deviceCount.toString());
        }
        return deviceConnectionString;
    }
    renderNavigator() {
        return (
            <RootNavigator
                ref={nav => {
                    this.navigator = nav;
                }}
                onNavigationStateChange={(prevState, currentState) => {
                    this.handleNavSceneChange(prevState, currentState);
                }} />
        )
    }
    handleNavSceneChange(prevState, currentState) {
        const currentScreen = NavUtils.getCurrentRouteNameFromState(currentState);
        this.currentPageId = currentScreen;
        this.updateStatusBarStyle(currentScreen);
    }
    renderXXerlay() {
        // Workaround for Android position absolute bug
        // issue : https://github.com/facebook/react-native/issues/8923
        let visible = this.state.isMenuVisible;
        return (
            <TouchableWithoutFeedback
                onPress={() => { this.hideMenu() }}>
                <View style={[styles.XXerlayView, { height: visible ? null : 0 }]} />
            </TouchableWithoutFeedback>
        )
    }
    renderSyncXXerlay() {
        let visible = this.props.pageStatus.syncModal;
        if (!visible) {
            return null;
        }
        return (
            <XXSyncXXerlay

                visible={visible} />
        )
    }
    //
    // EVENTS
    //
    onPressMenu(pageId) {
        requestAnimationFrame(() => {
            if (this.currentPageId !== pageId) {
                if (pageId === 'DemoTestPage') {
                    NavUtils.push(this.navigator, pageId);
                }
                else {
                    NavUtils.resetTo(this.navigator, pageId);
                }
                this.updateStatusBarStyle(pageId);
            }
            this.hideMenu();
        });
    }
    onPressLogout() {
        this.setState({ loggingOut: true }, () => {
            this.props.logout();
        });
    }
    onUpdateMenu(isMenuVisible) {
        if (isMenuVisible === undefined || this.previousMenuVisible === isMenuVisible) {
            return;
        }
        this.previousMenuVisible = isMenuVisible;

        // When menu needs to be opened
        if (isMenuVisible) {
            StatusBarManager.setStyle('light-content', isMenuVisible);
            Animated.timing(
                this.state.animatedPosition,
                {
                    tXXalue: {
                        // Animate the RootPage to the right.
                        // x: 317 / 375 * DEVICEINFO.SCREEN_WIDTH,
                        // y: 126 / 667 * DEVICEINFO.SCREEN_HEIGHT,
                        x: 317 / 375 * DEVICEINFO.SCREEN_WIDTH,
                        y: 1 / 1000 * DEVICEINFO.SCREEN_HEIGHT
                    },
                    // duration: 300
                    // debugging mode
                    duration: 300
                }
            ).start();
            return;
        }
        // When menu needs to be closed
        StatusBarManager.setStyle(this.routeStatusBarStyle, isMenuVisible);
        Animated.timing(
            this.state.animatedPosition,
            {
                tXXalue: {
                    x: 0,
                    y: 0
                },
                duration: 300
            }
        ).start();
    }
    //
    // Methods
    //
    initializeBluetooth() {
        // Event listeners for XXBluetoothManager
        this.itemDeviceStatusChanged = XXBluetoothEventEmitter.addListener('itemDeviceStatusChanged', event => {
            // console.log('ROotpage; . initializeBluetooth: ', event)
            this.getConnectedDevice();
        });
        this.getConnectedDevice();
    }
    destroyBluetooth() {
        if (this.itemDeviceStatusChanged) {
            this.itemDeviceStatusChanged.remXXe();
        }
    }
    getConnectedDevice() {
        console.log('when does getconnectedDevice get fired inside rootpage? :D', this.props)
        XXBluetoothManager.getDeviceAddress((error, address) => {
            if (error) {
                // Not connected
                this.setState({ deviceAddress: null });
                return;
            }
            // console.log('when can we read error, address', error, address)
            this.setState({ deviceAddress: address });
        });
    }
    initAndroidHardwareBackEvent() {
        BackHandler.addEventListener('hardwareBackPress', () => {
            if (!this.navigator) {
                return false;
            }
            if (this.navigator.state.index > 0) {
                const backAction = NavigationActions.back({
                    key: null
                });
                this.navigator.dispatch(backAction);
                return true;
            }
            return false;
        });
    }
    toggleMenu() {
        this.props.toggleRootMenu();
    }
    hideMenu() {
        this.props.closeRootMenu();
    }
}

const mapStateToProps = (state) => {
    return {
        signinStatus: state.page.signin,
        pageStatus: state.page.root,
        profile: state.user.profile,
        devices: state.device.devices,
        aDeviceHasBeenConnected: state.device.aDeviceHasBeenConnected,
    }
}
const mapDispatchToProps = (dispatch) => {
    return {
        logout: () => {
            dispatch(logout());
        },
        closeSyncModal: () => {
            dispatch(closeSyncModal());
        },
        toggleRootMenu: () => {
            dispatch(toggleRootMenu());
        },
        openRootMenu: () => {
            dispatch(openRootMenu());
        },
        closeRootMenu: () => {
            dispatch(closeRootMenu());
        },
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(RootPage);

const styles = StyleSheet.create({
    rootView: {
        flex: 1,
        flexDirection: 'column',
    },
    menuView: {
        width: DEVICEINFO.SCREEN_WIDTH,
        height: '100%',
        backgroundColor: '#aab942',
        position: 'absolute',
        top: 0,
        left: 0
    },
    menuTopArea: {
        backgroundColor: '#b7c846',
        // height: DEVICEINFO.SCREEN_HEIGHT * 0.35,
        height: DEVICEINFO.SCREEN_HEIGHT * 0.28,
        width: '100%',
        flexDirection: 'column',
    },
    menuBottomArea: {
        // backgroundColor: '#aab942',
        width: '100%',
        flex: 1,
        flexDirection: 'column',
    },
    animatedView: {
        position: 'relative',
        flex: 1,
        flexDirection: 'column',
        backgroundColor: '#fff'
    },
    profileImageSubContainer: {
        height: '100%',
        flexDirection: 'column',
        justifyContent: 'center',
        marginLeft: 40,
        marginTop: 10,
    },
    profileImage: {
        width: DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 70 : 80,
        height: DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 70 : 80,
        borderRadius: (DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 70 : 80) / 2
    },
    profileText: {
        marginTop: DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 6 : 16,
        fontSize: Math.min(LAYOUTINFO.DESIGN_WIDTH_RATIO * 20, 21),
        color: '#fff',
        backgroundColor: 'transparent'
    },
    deviceText: {
        marginTop: DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 6 : 16,
        fontSize: Math.min(LAYOUTINFO.DESIGN_WIDTH_RATIO * 14, 15),
        color: '#fff',
        backgroundColor: 'transparent'
    },
    menuContainer: {
        flex: 1,
        width: '100%',
        height: '100%',
        flexDirection: 'column',
        alignItems: 'flex-start',
    },
    // menubutton
    menuButtonTouch: {
        marginTop: 25 * HEIGHT_RATIO,
        marginLeft: 38,
    },
    menuButtonView: {
        flexDirection: 'row',
        alignItems: 'center'
    },
    menuIcon: {
        width: 18,
        height: 18,
        resizeMode: 'contain'
    },
    // menubuttontext
    menuText: {
        marginLeft: 17,
        fontSize: Math.min(LAYOUTINFO.DESIGN_WIDTH_RATIO * 22, 22),
        color: '#fff'
    },
    XXerlayView: {
        position: 'absolute',
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        width: null,
        height: null,
        backgroundColor: 'rgba( 255, 255, 255, 0.0001 )',
        zIndex: 9999
    }
});

这是RootNavigator页面

import { Platform } from 'react-native';
import { StackNavigator } from 'react-navigation';
// Pages
import EntryPage from '../EntryPage/EntryPage';
import SigninPage from '../SigninPage/SigninPage';
import SignupPage from '../SignupPage/SignupPage';
import ReportSinglePage from '../ReportSinglePage/ReportSinglePage';
import HomePage from '../HomePage/HomePage';
import VolumePage from '../VolumePage/VolumePage';
import ReportPage from '../ReportPage/ReportPage';
import ReportDetailPage from '../ReportDetailPage/ReportDetailPage';
import ItemListPage from '../ItemListPage/ItemListPage';
import AddItemPage from '../AddItemPage/AddItemPage';
import SupportPage from '../SupportPage/SupportPage';
import SettingsPage from '../SettingsPage/SettingsPage';
import SoundPage from '../SoundPage/SoundPage';
import VerticalSoundPage from '../SoundPage/VerticalSoundPage';
import SoundSyncPage from '../SoundSyncPage/SoundSyncPage';
import TestPage from '../TestPage/TestPage';
import iOSTestPage from '../TestPage/iOSTestPage';
import FittingTestPage from '../TestPage/FittingTestPage';
import SendResultSlide from '../SoundSyncPage/SendResultSlide';
import ModePage from '../ModePage/ModePage';
import PolicyPage from '../PolicyPage/PolicyPage';
import PrivacyPage from '../PrivacyPage/PrivacyPage';
import TermsAndConditionsPage from '../TermsAndConditionsPage/TermsAndConditionsPage';

import SelectTutorialPage from '../TutorialPage/SelectTutorialPage';
import PreparingTutorial from '../TutorialPage/PreparingTutorial';
import AddItemTutorial from '../TutorialPage/AddItemTutorial';
import HearingTestTutorial from '../TutorialPage/HearingTestTutorial';
import ReportTutorial from '../TutorialPage/ReportTutorial';
import EqualizerTutorial from '../TutorialPage/EqualizerTutorial';
import AddItemTutorialCompletion from '../TutorialPage/AddItemTutorialCompletion';
import AddItemTutorialFailure from '../TutorialPage/AddItemTutorialFailure';
import HearingTestTutorialCompletion from '../TutorialPage/HearingTestTutorialCompletion';
// import RootPage from '../RootPage/RootPage';



const RootNavigator = StackNavigator(
    {
        // RootPage: {screen: RootPage},
        EntryPage: { screen: EntryPage },
        SignupPage: { screen: SignupPage },
        HomePage: { screen: HomePage },
        TestPage: { screen: TestPage },
        iOSTestPage: { screen: iOSTestPage },
        FittingTestPage: { screen: FittingTestPage },
        ReportPage: { screen: ReportPage },
        ReportDetailPage: { screen: ReportDetailPage },
        ReportSinglePage: { screen: ReportSinglePage },
        ItemListPage: { screen: ItemListPage },
        AddItemPage: { screen: AddItemPage },
        SoundPage: { screen: VerticalSoundPage },
        SoundSyncPage: { screen: SoundSyncPage },
        SupportPage: { screen: SupportPage },
        SettingsPage: { screen: SettingsPage },
        VolumePage: { screen: VolumePage },
        SendResultSlide: { screen: SendResultSlide },
        PolicyPage: { screen: PolicyPage },
        PrivacyPage: { screen: PrivacyPage },
        TermsAndConditionsPage: { screen: TermsAndConditionsPage },
        SelectTutorialPage: { screen: SelectTutorialPage },
        PreparingTutorial: { screen: PreparingTutorial },
        AddItemTutorial: { screen: AddItemTutorial },
        HearingTestTutorial: { screen: HearingTestTutorial },
        ReportTutorial: { screen: ReportTutorial },
        EqualizerTutorial: { screen: EqualizerTutorial },
        AddItemTutorialCompletion: { screen: AddItemTutorialCompletion },
        AddItemTutorialFailure: { screen: AddItemTutorialFailure },
        HearingTestTutorialCompletion: { screen: HearingTestTutorialCompletion },
    },
    {
        initialRouteName: 'EntryPage',
        navigationOptions: {
            header: null,
        }
    },
    {
        headerMode: 'none'
    }
);

export default RootNavigator;

以防万一,这是我要使用的辅助函数:

  static push(navigator, pageId, params = {}) {
        let newParams = { navIndex: 1 };
        if (navigator.state.index) {
            newParams.navIndex = navigator.state.index + 1;
        }
        else if (navigator.state.params && navigator.state.params.navIndex) {
            newParams.navIndex = navigator.state.params.navIndex + 1;
        }
        Object.assign(newParams, params);
        navigator.dispatch({ type: 'Navigation/NAVIGATE', routeName: pageId, params: newParams });
    }

0 个答案:

没有答案