javascript - 如何在选项卡聚焦事件上调用异步方法?

标签 javascript react-native react-navigation tabnavigator

我正在制作一个应用程序,根据进入时间和退出时间记录记录保存时间和到期时间。

当前情况:-

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

我面临的问题:-

由于我使用 AsyncStorage 在“主页”选项卡本身中设置计算的到期时间或已保存时间的项目,因此我调用函数 getDueTime() 来获取 中的项目Dues.js 中的 >compoundDidMount() 方法,但仅工作一次,因为 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'
    }
});

提前致谢。

最佳答案

您并没有真正弄清楚为什么您无法使用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 导出为 react-navigation 已使用的 TabNavigator。只需将其命名为 AppNavigator/AppNavigation 即可。

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

希望这有帮助

关于javascript - 如何在选项卡聚焦事件上调用异步方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49422833/

相关文章:

javascript - 如何在屏幕上定位元素?

ios - 如何在 native react 中检测同时发生的 onPress 事件?

javascript - React-Redux 连接无法从 Provider 获取存储

javascript - React Native with react-navigation and Redux - 如何实现全局可用的 'Sign Out' 按钮

javascript - 使用 React 抽屉导航时如何处理 iOS 上的后退按钮?

javascript - 这是安全连接吗?

javascript - 模拟一个 "ontype"事件

reactjs - 如何对react-native-svg多边形元素进行动画处理?

javascript - 如何清理 React Native 中类组件的状态?

javascript - 如何像电子表格一样进行基于网络的 "table"选择? (矩形区域与行环绕选择)