如何在特定于选项卡的事件上调用异步方法?

时间:2018-03-22 07:25:12

标签: javascript react-native react-navigation tabnavigator

我正在制作一个应用程序,根据录入时间记录节省时间和截止时间,并记录退出时间。

当前情况: -

  • App.js用于TabNavigator选项并将默认选项卡设置为Home
  • Home.jsDues.jsSavings.js分别用于显示标签的内容
  • 3个标签:家庭,会费和储蓄
  • 主页选项卡:记录输入时间和退出时间
  • 会费标签:根据主页选项卡中记录的进入和退出时间显示到期时间
  • 储蓄标签:根据首页标签中记录的进入和退出时间显示储蓄时间

我面临的问题: -

由于我使用AsyncStorage在“主页”标签中设置计算到期时间或节省时间的项目,因此我调用函数getDueTime()compoundDidMount()方式获取Dues.js方法中的项目但是,因为compoundDidMount()方法在聚焦选项卡时工作只有一次,就像在聚焦时初始化选项卡一样,它将调用compoundDidMount()方法。 但是每次选项卡聚焦时我都想调用函数getDueTime(),以便我得到实时计算结果。

我是ReactNative的新手,我知道有onNavigationStateChange()方法,但我无法使用它。请指导我解决这个问题。

App.js

import React from 'react'
import {TabNavigator, TabBarTop} from 'react-navigation'
import Home from './tabs/Home'
import Dues from './tabs/Dues'
import Savings from "./tabs/Savings";

export default TabNavigator(
    {
        Dues: {
            screen: Dues,
            navigationOptions: {
                tabBarLabel: 'Dues',
            },
        },

        Home: {
            screen: Home,
            navigationOptions: {
                tabBarLabel: 'Home',
            },

        },

        Savings: {
            screen: Savings,
            navigationOptions: {
                tabBarLabel: 'Savings',
            },
        },
    },
    {
        tabBarComponent: TabBarTop,
        initialRouteName: 'Home',
        tabBarOptions: {
            labelStyle: {
                fontSize: 23,
            },
            style: {
                backgroundColor: '#4CAF50'
            },
            indicatorStyle: {
                backgroundColor: 'white'
            },
            inactiveTintColor: '#1A237E',
            upperCaseLabel: false
        }
    }
);

Home.js

import React from 'react'
import {StyleSheet, Text, View, AsyncStorage} from 'react-native'
import {Button} from "../components/Button"
import Moment from 'moment'

export default class Home extends React.Component {

    entry = new Moment();
    exit = new Moment();
    duration = 0;

    constructor(props) {
        super(props);
        this.state = {
            curEntryTime: null,
            curExitTime: null,
            count: 2,
            savings: 0,
            dues: 0,
            btnTitle: 'Office Entry',
            visible: true
        };
    }

    onPress = () => {
        this.setState({
            count: --this.state.count
        });
        if (this.state.count === 1) {
            this.setState({
                btnTitle: 'Office Exit',
                curEntryTime: Moment().utc().local().format('hh:mm A')
            });
            this.setEntryTime();
        }
        else {
            this.setState({
                btnTitle: ' ',
                visible: !this.state.visible,
                curExitTime: Moment().utc().local().format('hh:mm A'),
            });
            this.setExitTime();
        }
    };

    //For Testing
    resetData = () => {
        AsyncStorage.removeItem('entryTime');
        AsyncStorage.removeItem('exitTime');
        //AsyncStorage.clear();
    };

    setEntryTime() {
        let obj = {
            btnTitleVar: 'Office Exit',
            countVar: this.state.count,
            curEntryTimeVar: Moment().utc().local().format('hh:mm A')
        };
        this.entry = Moment(obj.curEntryTimeVar, "hh:mm A");
        AsyncStorage.setItem('entryTime', JSON.stringify(obj)).catch((errors) => console.log(errors));
    };

    setExitTime() {
        let obj = {
            btnTitleVar: ' ',
            countVar: this.state.count,
            visibleVar: !this.state.visible,
            curExitTimeVar: Moment().utc().local().format('hh:mm A')
        };
        this.exit = Moment(obj.curExitTimeVar, "hh:mm A");
        AsyncStorage.setItem('exitTime', JSON.stringify(obj)).catch((errors) => console.log(errors));

        this.duration = Moment.duration(this.exit.diff(this.entry)).asMinutes();

        /**
          * --------------------------------
          * | Logic To Calculate SavedTime |
          * |                              |
          * |                              |
          * |                              |
          * --------------------------------
          */
        JSON.stringify(savedTime)).catch((errors) => console.log(errors));
        }
        
        /**
          * --------------------------------
          * | Logic To Calculate DueTime   |
          * |                              |
          * |                              |
          * |                              |
          * --------------------------------
          */
        JSON.stringify(dueTime)).catch((errors) => console.log(errors));
        }
    };

    getEntryTime = async () => {
        let entryTime = await AsyncStorage.getItem('entryTime');
        let parsedData = JSON.parse(entryTime);
        if (parsedData !== null) {
            this.setState({btnTitle: parsedData.btnTitleVar});
            this.setState({count: parsedData.countVar});
            this.setState({curEntryTime: parsedData.curEntryTimeVar});
        }
    };

    getExitTime = async () => {
        let exitTime = await AsyncStorage.getItem('exitTime');
        let parsedData = JSON.parse(exitTime);
        if (parsedData !== null) {
            this.setState({btnTitle: parsedData.btnTitleVar});
            this.setState({count: parsedData.countVar});
            this.setState({visible: parsedData.visibleVar});
            this.setState({curExitTime: parsedData.curExitTimeVar});
        }
    };

    getDueTime = async () => {
        let dueTime = await AsyncStorage.getItem('dueTime');
        let parsedDueTime = JSON.parse(dueTime);
        if (parsedDueTime !== null) {
            //DueTime state set in Home Tab
            this.setState({dues: parsedDueTime.duesVar});
        }
    };

    getSavingTime = async () => {
        let savedTime = await AsyncStorage.getItem('savedTime');
        let parsedSavedTime = JSON.parse(savedTime);
        if (parsedSavedTime !== null) {
            //SavedTime state set in Home Tab
            this.setState({savings: parsedSavedTime.savingsVar});
        }
    };

    componentDidMount() {
        this.getEntryTime().done();
        this.getExitTime().done();
        this.getDueTime().done();
        this.getSavingTime().done();
        //alert(this.state.exitTime.diff(this.state.entryTime))
    }

    render() {
        return (
            <View style={styles.container}>
                <View style={styles.container}>
                    <View style={[styles.textContainer, {flexDirection: 'row'}]}>
                        <Text style={[styles.textBody, {color: 'green'}]}>In Time:</Text>
                        <Text style={[styles.textBody, {color: 'green'}]}>{this.state.curEntryTime}</Text>
                    </View>
                    <View style={[styles.textContainer, {flexDirection: 'row'}]}>
                        <Text style={[styles.textBody, {color: 'red'}]}>Out Time:</Text>
                        <Text style={[styles.textBody, {color: 'red'}]}>{this.state.curExitTime}</Text>
                    </View>
                </View>
                <View style={[styles.container, {flex: 1.5}]}>
                    <View style={styles.displayButtonContainer}>
                        {this.state.visible ? <Button sendData={() => this.state.count <= 0 ? null : this.onPress()}
                                                      count={this.state.count}
                                                      title={this.state.btnTitle}/> : (null,
                            <Text style={[styles.textBody, {textAlign: 'center', color: '#1A237E'}]}>
                                {'Swipe Right To See Dues\n\nSwipe Left to See Savings'}
                            </Text>)}
                    </View>
                    <View style={styles.resetButtonContainer}>
                        <Button sendData={() => this.resetData()} title={'Reset'}/>
                    </View>
                </View>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#81C784'
    },
    textContainer: {
        flex: 1,
        justifyContent: 'center',
        paddingLeft: 50,
        paddingTop: 40,
        backgroundColor: 'white'
    },
    displayButtonContainer: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        padding: 50
    },
    resetButtonContainer: {
        justifyContent: 'center',
        alignItems: 'center',
    },
    textBody: {
        flex: 1,
        fontSize: 25,
        fontWeight: '600'
    }
});

Dues.js

import React from 'react'
import {StyleSheet, Text, View, AsyncStorage} from 'react-native'
import {Button} from "../components/Button"

export default class Dues extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            dueTime: 0
        };
    }

    resetData = () => {
        AsyncStorage.removeItem('dueTime');
    };

    //I want to call this function whenever Dues Tab is focused. 
    getDueTime = async () => {
        let dueTime = await AsyncStorage.getItem('dueTime');
        let parsedDueTime = JSON.parse(dueTime);
        if (parsedDueTime !== null) {
            this.setState({dueTime: parsedDueTime.duesVar});
        }
    };



    /*This function calls getDueTime only when tab is focused for the first time. After that, I will have to open the app again to see the changed dueTime the next time entry and exit time is recorded*/
    componentDidMount() {
        this.getDueTime().done()
    }

    render() {
        return (
            <View style={styles.container}>
                <View style={styles.container}>
                    <View style={[styles.textContainer, {flexDirection: 'row'}]}>
                        <Text style={[styles.textBody, {color: 'red'}]}>Current Dues:</Text>
                        <Text style={[styles.textBody, {color: 'red'}]}>{this.state.dues}</Text>
                    </View>
                </View>
                <View style={[styles.container, {flex: 1.5, justifyContent: 'flex-end'}]}>
                    <View style={styles.resetButtonContainer}>
                        <Button sendData={() => this.resetData()} title={'Reset'}/>
                    </View>
                </View>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#81C784'
    },
    textContainer: {
        flex: 1,
        justifyContent: 'center',
        paddingLeft: 50,
        paddingTop: 40,
        backgroundColor: 'white'
    },
    displayButtonContainer: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        padding: 50
    },
    resetButtonContainer: {
        justifyContent: 'center',
        alignItems: 'center',
    },
    textBody: {
        flex: 1,
        fontSize: 25,
        fontWeight: '600'
    }
});

提前致谢。

1 个答案:

答案 0 :(得分:1)

你没有真正澄清为什么你不能使用onNavigationStateChange(),因为你应该完全使用它! :)

我可以提出以下建议: 有这样的结构:

AppNavigation - rename App to this
App - imports AppNavigation | root of app and state container
  return (
    <View>
      <AppNavigation
        onNavigationStateChange={(prevState, newState) => {
          console.log(newState)
          /** 
            {
              "index":0,
              "routes":[
                {
                  "type":"Navigation/NAVIGATE",
                  "routeName":"Home",
                  "routes":[
                    {
                      "key":"Dues",
                      "routeName":"Dues"
                    },
                    {
                      "key":"Savings",
                      "routeName":"Savings"
                    }
                  ],
                  "index":1,
                  "key":"id-1521725309375-1"
                }
              ]
            }
          **/

          // important is the "index":1
          // it indicates which tab is the currently active one
          // in this case you are currently on the 'Savings' Tab
        }}

      />

    </View>
);

另请注意,不要将TabNavigator导出为TabNavigator已使用的react-navigation。只需将其称为AppNavigator / AppNavigation

此外,此结构有助于拥有不受屏幕限制的应用程序范围样式。想象一下,你想要一个顶部标题,表示错误或警告。您现在可以独立显示选项卡/屏幕。

希望这有帮助