您能看到为什么React Native中的DeviceEventEmitter运行两次吗?

时间:2018-08-02 17:14:37

标签: android react-native redux

从“ Home.js”访问“ MyShows.js”屏幕后,一旦返回“ Home.js”并按一个键,事件监听器将开始运行两次。已经看了几个小时,并测试了一切的感觉。在有人创建“ Home.js”组件之后,我添加了“ MyShows.js”组件。可以很好地访问任何其他屏幕,例如“指南”。您可以在我的代码中看到问题所在吗?使用React导航将它们连接起来,将省略Redux代码。让我知道您是否需要更多信息。

Home.js

import React, { Component } from 'react';
import { ActivityIndicator, AppState, BackHandler, DeviceEventEmitter, Image, StyleSheet, Text, View } from 'react-native';

// Components
import TopBar from '../Common/TopBarContainer';
import CardList from './CardList';
import HomeMenu from './Containers/HomeMenuContainer';

// Mock Data
import { mockCards } from '../../assets/mock';

export default class Home extends Component {

    constructor() {
        super();
        this.state = {
            isCardsShowing: false,
            cards: mockCards,
            menu: [
                {
                    menuTitle: 'MY SHOWS',
                    menuCallback: () => this.props.currentPage === 'Home' && this.navigate('MyShows')
                },
                {
                    menuTitle: 'WHAT TO WATCH',
                    menuCallback: () => this.props.currentPage === 'Home' && console.log('What to watch')
                },
                {
                    menuTitle: 'GUIDE',
                    menuCallback: () => this.props.currentPage === 'Home' && this.navigate('Guide')
                },
                {
                    menuTitle: 'SEARCH',
                    menuCallback: () => this.props.currentPage === 'Home' && this.navigate('Search')
                },
                {
                    menuTitle: 'SETTINGS',
                    menuCallback: () => this.props.currentPage === 'Home' && this.navigate('Menu')
                }
            ]
        }
    }

    shouldComponentUpdate(nextProps) {
        return nextProps.currentPage === 'Home';
    }

    componentDidMount() {
        BackHandler.addEventListener('hardwareBackPress', () => true);
        if (!this._homeEventEmitter) {
            this._homeEventEmitter = DeviceEventEmitter.addListener('onKeyDown', this._listenerFunction);
        }
        setTimeout(() => {
            this.setState({ isCardsShowing: true });
            if (!this._homeEventEmitter) {
                this._homeEventEmitter = DeviceEventEmitter.addListener('onKeyDown', this._listenerFunction);
            }
        }, 3500);
        // Become inactive/active scroll view issue -- START
        // var backgroundStartTime;
        AppState.addEventListener('change', (nextAppState) => {
            if (nextAppState === 'background') {
                // backgroundStartTime = new Date();
                this.setState({ isCardsShowing: false });
            } else {
                setTimeout(() => {
                    this.setState({ isCardsShowing: true });
                    if (!this._homeEventEmitter) {
                        this._homeEventEmitter = DeviceEventEmitter.addListener('onKeyDown', this._listenerFunction);
                    }
                }, 3500);
            }
        }); // Become inactive/active scroll view issue -- END
    }

    componentWillReceiveProps(nextProps) {
        if (this.props.currentPage !== 'Home' && nextProps.currentPage === 'Home') {
            // Solves scroll view issue -- START
            this.setState({ isCardsShowing: false });
            setTimeout(() => {
                this.setState({ isCardsShowing: true });
                if (!this._homeEventEmitter) {
                    this._homeEventEmitter = DeviceEventEmitter.addListener('onKeyDown', this._listenerFunction);
                }
            }, 3500);
            setTimeout(() => this.refs.cardList && this.refs.cardList.refs.cardList.scrollToIndex({ index: nextProps.selectedCard, viewOffset: 100 }), 3550);
            // Solves scroll view issue -- END
        }
    }

    _listenerFunction = (keyEvent) => {

        const { selectedCard, isMenuEnabled, onToggleMenu, onChangeCard } = this.props;

        if (this.props.currentPage === 'Home') {
            if (keyEvent.keyCode === 19) { // Up
                onToggleMenu(true);
            }
            if (keyEvent.keyCode === 20) { // Down
                onToggleMenu(false);
            }
            if (keyEvent.keyCode === 21) { // Left
                if (!isMenuEnabled) {
                    this.state.cards.unshift(this.state.cards[this.state.cards.length - 1]);
                    this.state.cards.pop();
                    this.forceUpdate();
                }
            }
            if (keyEvent.keyCode === 22) { // Right
                if (!isMenuEnabled) {
                    this.state.cards.push(this.state.cards[0]);
                    this.state.cards.shift();
                    this.forceUpdate();
                }
            }
            if (keyEvent.keyCode === 23 || keyEvent.keyCode === 66) { //Select (OK)
                if (!isMenuEnabled) {
                    this._homeEventEmitter.remove();
                    this._homeEventEmitter = null;
                    this.props.navigation.navigate('ShowInfo', { cardInfo: this.state.cards[selectedCard] });
                }
            }
        }
    }

    componentWillUnmount() {
        this._homeEventEmitter && this._homeEventEmitter.remove();
        this._homeEventEmitter = null;
    }

    navigate = (page) => {
        if(page === 'Menu') {
            this.props.onStopLiveTV();
        }
        this.props.onChangePage(page);
        this.props.navigation.navigate(page);
    }

    render() {

        const { currentTime, height, width, navigation } = this.props.screenProps;
        const { cards, menu } = this.state;
        const { routeName } = this.props.navigation.state;
        const { currentPage, selectedCard, isMenuEnabled, isPlayerShowing } = this.props;

        return (
            routeName === 'Home' ?
                <View style={styles.mainContainer}>
                    <View style={{ position: 'absolute', height, width }}>
                        <Image source={{ uri: cards[selectedCard].image }} resizeMode='cover' style={{ flex: 1 }} />
                    </View>
                    <TopBar
                        currentTime={currentTime}
                        topBarText='HOME'
                        pushInTime={isPlayerShowing} />
                    <View style={{ flex: 11.5, paddingVertical: 20, backgroundColor: 'rgba(0, 0, 0, 0.75)' }}>
                        <View style={{ flex: 1, justifyContent: 'flex-end' }}>
                            <HomeMenu menuItems={menu} isEnabled={isMenuEnabled} currentPage={currentPage} />
                        </View>
                        <View style={{ flex: 1, justifyContent: 'center' }}>
                            {
                                this.state.isCardsShowing ?
                                    <CardList
                                        ref='cardList'
                                        cards={cards}
                                        selectedCard={selectedCard}
                                        isEnabled={!isMenuEnabled} 
                                        showHeaderText={true} /> :
                                    <ActivityIndicator size={50} color='#D3D3D3' />
                            }
                        </View>
                    </View>
                    <View style={styles.footer}>
                        <Text style={{ color: '#CBBB56', fontSize: 18 }}>A</Text>
                        <Text style={styles.footerText}>options</Text>
                    </View>
                </View> : null
        );
    }
}

HomeMenu.js

import React, { Component } from 'react';
import { BackHandler, DeviceEventEmitter, StyleSheet, FlatList, ScrollView, Image, Text, View } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
// import * as Animatable from 'react-native-animatable';

export default class HomeMenu extends Component {

    componentDidMount() {
        BackHandler.addEventListener('hardwareBackPress', () => true);
        if (!this._homeMenuEmitter) {
            this._homeMenuEmitter = DeviceEventEmitter.addListener('onKeyDown', this._listenerFunction);
        }
    }

    _listenerFunction = (keyEvent) => {

        const { menuIndex, isEnabled, menuItems, changeMenuIndex, currentPage } = this.props;

        if (isEnabled && currentPage === 'Home'){
            if (keyEvent.keyCode === 21) { // Left
                if (menuIndex > 0) {
                    changeMenuIndex(menuIndex - 1);
                    // this.refs.cardList.refs.cardList.scrollToIndex({ index: this.state.selectedCard - 1, viewOffset: 100});
                }
            }
            if (keyEvent.keyCode === 22) { // Right
                if (menuIndex < 4) {
                    changeMenuIndex(menuIndex + 1);
                    // this.refs.cardList.refs.cardList.scrollToIndex({ index: this.state.selectedCard - 1, viewOffset: 100});
                }
            }
            if (keyEvent.keyCode === 23 || keyEvent.keyCode === 66) { //Select (OK)
                if (menuItems[menuIndex].menuCallback) {
                    menuItems[menuIndex].menuCallback();
                }
            }
        }
    }

    render() {

        const { menuIndex, menuItems, isEnabled } = this.props;

        return (
            <View style={styles.menuContainer}>
                {
                    menuItems.map((menuItem, i) => (
                        <View key={i} style={[styles.menuItemContainer]}>
                            {
                                menuItem.menuTitle === 'SETTINGS' ?
                                    <Icon key={i} name="cog" size={30} color={menuIndex === i && isEnabled ? '#eaeaea' : '#909090'}/> :
                                    <Text style={menuIndex === i && isEnabled ? styles.selectedMenuText : styles.menuText}>{menuItem.menuTitle}</Text>
                            }
                        </View>
                    ))
                }
            </View>
        );
    }
}

MyShows.js

import React, { Component } from 'react';
import { ActivityIndicator, DeviceEventEmitter, BackHandler, StyleSheet,FlatList, Image, Text, View } from 'react-native';
import TopBar from '../Common/TopBarContainer';
import { mockCards } from '../../assets/mock';
import MyShowsCardList from './MyShowsCardList';

export default class MyShows extends Component {
    constructor() {
        super()


    }

    _keyExtractor = (item, index) => index.toString();

    _renderItem = ({ item, index }) => (
        this.props.titlesIndex === index && this.props.cardsEnabled === false ?
        <View style={[styles.selectedTextContainer, {width: this.props.screenProps.width}]}>
            <View style={styles.textContainer}>
                <Text style={{ fontFamily: 'OpenSans-Regular', color: 'black', fontSize: 22, marginLeft: 10 }}>
                    {item.program_name}
                </Text>
            </View>
        </View>
        :
        <Text style={{ marginLeft: 80, color: '#EAEAEA', fontFamily: 'OpenSans-Light', fontSize: 22 }}>
            {item.program_name}
        </Text>
    );

    shouldComponentUpdate(nextProps) {
        return nextProps.currentPage === 'MyShows';
    }

    componentDidMount() {
        BackHandler.addEventListener('hardwareBackPress', () => true);
        if(!this._myShowsEventEmitter)
            this._myShowsEventEmitter = DeviceEventEmitter.addListener('onKeyDown', this._listenerFunction);
        this.props.onUpdateCards(mockCards);
        this.props.onGetAssets(614);
    }

    _listenerFunction = (keyEvent) => {

        if (this.props.currentPage === 'MyShows') {
            if (keyEvent.keyCode === 19) { // Up
                console.log("UP");
                if(this.props.titlesIndex === 0 && this.props.cardsEnabled === false){
                    this.props.onCardMenuToggle(!this.props.cardsEnabled);
                }else if(this.props.cardsEnabled === false){
                    this.props.onChangeTitlesIndex(this.props.titlesIndex - 1);
                }else{
                    console.log("Card menu already activated")
                }     
            }

            if (keyEvent.keyCode === 20) { // Down
                console.log("DOWN");
                if(this.props.cardsEnabled){
                    //Collapsing animation goes here
                    this.props.onCardMenuToggle(!this.props.cardsEnabled);
                }else if(this.props.assetData.length > (this.props.titlesIndex + 1)){
                    this.props.onChangeTitlesIndex(this.props.titlesIndex + 1);
                }else{
                    console.log("Max titles reached");
                }
            }

            if (keyEvent.keyCode === 21) { // Left
                if(this.props.cardsEnabled){
                    console.log("LEFT");
                    this.props.onMoveLeft(this.props.cardData);
                    console.log(this.props.cardData);
                    // this.forceUpdate();
                }
            }
            if (keyEvent.keyCode === 22) { // Right
                if(this.props.cardsEnabled){
                    console.log("RIGHT");
                    this.props.onMoveRight(this.props.cardData);
                    console.log(this.props.cardData);
                }
            }

            // UPDATE BASED ON CARD OR TITLE SELECTED
            if (keyEvent.keyCode === 23 || keyEvent.keyCode === 66) { //Select (OK)
                this._myShowsEventEmitter.remove();
                this._myShowsEventEmitter = null;
                this.props.onChangePage('SelectedRecording');
                this.props.navigation.navigate('SelectedRecording');
            }

            if (keyEvent.keyCode === 4 || keyEvent.keyCode === 111) { //Back
                this._myShowsEventEmitter.remove();
                this._myShowsEventEmitter = null;
                this.props.onChangePage('Home');
                this.props.navigation.navigate('Home');
            }
        }
    }

    componentWillUnmount() {
        this._myShowsEventEmitter && this._myShowsEventEmitter.remove();
    }


    render() {
        const { currentTime, height, width, navigation } = this.props.screenProps;

        const prependedCards = [{name: 'View: RECORDINGS', id: 0 }, ...this.props.cardData];

        return (
            <View style={styles.mainContainer}>
                <View style={{ position: 'absolute', height, width }}>
                {/* Placeholder Image */}
                    <Image source={{ uri: this.props.cardData[0].image }} resizeMode='cover' style={{ flex: 1 }} />
                </View>
                <TopBar
                        currentTime={currentTime}
                        topBarText='MY SHOWS'
                        pushInTime={false} //Change to isPlayerShowing prop 
                        dvrMemory={true}
                />
                <View style={{ flex: 11.5, paddingVertical: 20, backgroundColor: 'rgba(0, 0, 0, 0.75)' }}>
                    <View style={{ flex: 1, justifyContent: 'center' }}>
                        {/* UPDATE isCardsShowing  */}
                        {/* { this.props.subscriberData.data !== undefined && 
                          this.props.subscriberData.data.length > 0 && */}
                        {/* } */}
                        {/* Placeholder items and id */}
                        {this.props.loading ?
                            <ActivityIndicator size={50} color='#D3D3D3' />
                            :
                            <View style={{ flex: 1, justifyContent: 'center' }}>
                                <MyShowsCardList
                                style={{ flex: 1 , paddingTop: 30 }}
                                // ref='cardList'
                                cards={this.props.cardData}
                                showHeaderText={false}
                                isEnabled={this.props.cardsEnabled} 
                                />
                                <FlatList
                                    style={{ flex: 2 }}
                                    contentContainerStyle={{ paddingTop: 20 }}
                                    data={this.props.assetData}
                                    renderItem={this._renderItem}
                                    keyExtractor={this._keyExtractor}
                                    extraData={this.props}
                                />    
                            </View>    
                        }            
                    </View>
                </View>
                <View style={styles.footer}>
                        <Text style={{ color: '#CBBB56', fontSize: 18, paddingLeft: 50 }}>A</Text>
                        <Text style={styles.footerText}>options</Text>
                        <Text style={{ color: '#397F8A', fontSize: 18, paddingLeft: 50 }}>B</Text>
                        <Text style={styles.footerText}>list sorted by name</Text>
                        <Text style={{ color: '#993F4E', fontSize: 18, paddingLeft: 50 }}>C</Text>
                        <Text style={styles.footerText}>recordings</Text>
                </View>
            </View>
        )   
    };
}

0 个答案:

没有答案