I have a notification alert that shows after 60 seconds of login, the problem is that if someone logout within those 60 seconds. the message still show even if the user is no longer logged-in.
below is what I tried to do to solve this problem, but without success. do I need
I have tried default export to export timerId but since react-native only allows one default export and this happened before this part of the code I could not use default export.
I tried to do export timerId; but I got an error saying unresolved variable.
index.js:
_myAlert= () => {
timerId: setTimeout(()=>{
Alert.alert(
'Notification',
'Please set up your user account.'
);
}, 60000)
}
drawer.js:
onPress={() => {
clearTimeout(this.timerId);
this.jumpToSection('Logout');
}
}
Maybe, you could have a scope problem.
Next link could be help
https://cybmeta.com/var-let-y-const-en-javascript
Here is one solution where timerhandle is cleared only in componentWillUnmount but the alert is shown only if button is not pressed.
App.js
import React, { Component } from 'react';
import { View, Alert } from 'react-native';
import ClearButton from './src/ClearButton'
class App extends Component {
constructor(props) {
super(props);
this.timerHandle = 0;
this.state = {
pressed: false
}
}
componentDidMount() {
this.timerHandle = setTimeout(() => {
if (!this.state.pressed) {
Alert.alert(
'Notification',
'Please set up your user account.'
);
}
}, 60000);
}
componentWillUnmount() {
if (this.timerHandle) {
clearTimeout(this.timerHandle);
}
}
onPress() {
this.setState({ pressed: true });
}
render() {
return (
<View>
<ClearButton onPress={this.onPress.bind(this)}/>
</View>
);
}
}
export default App;
ClearButton.js
import React, { Component } from 'react';
import { View, TouchableOpacity } from 'react-native';
class ClearButton extends Component {
render() {
return (
<TouchableOpacity onPress={this.props.onPress.bind(this)}>
<View style={{width: 100, height: 100, backgroundColor: '#0000ff'}}/>
</TouchableOpacity>
);
}
}
export default ClearButton;
I guess you could also clear the timer in App.js onPress method if you wish not to use this.state.pressed but you should still not remove the clearing in componentWillUnmount.
Related
I am using react-bootstrap version 0.32.4, I can't update the version, that will bring up many changes.
I want to have a tooltip info showing for 4 seconds on page load and then it should hide, after that the tool tip info should be shown on hover.
Below is the code:
import React from "react";
import "./styles.css";
import { Button, Tooltip, OverlayTrigger } from "react-bootstrap";
import { render } from "react-dom";
class App extends React.Component {
constructor(props){
super(props);
this.state = {
show: true
}
}
getTooltip = () => {
return <Tooltip id="tooltip">this is tooltip text</Tooltip>;
};
componentDidMount() {
console.log("ran")
setTimeout(function() {
this.setState({show: false})
}.bind(this), 4000);
}
render(){
console.log(`running for componet did update: ${this.state.show}`)
return (
<>
<OverlayTrigger
trigger={['hover', 'focus']}
defaultShow={this.state.show}
placement="right"
overlay={this.getTooltip()}
>
<Button>Click me!</Button>
</OverlayTrigger>
</>
);
}
}
export default App;
I am trying to use defaultShow but it is not doing anything. How can I achieve this functionality with react-bootstrap version 0.32.4
Below is the link to code sandbox:
https://codesandbox.io/s/react-bootstrap3-tooltip-jqnzqs
You can use useRef to get the overlay's functions for showing/hiding the tooltip within the overlay
Here is the sandbox
You also can look into the below implementation with some explanation in the code
import React from "react";
import "./styles.css";
import { Button, Tooltip, OverlayTrigger } from "react-bootstrap";
class App extends React.Component {
// const [isShowing, setIsShowing] = useState(true);
constructor(props) {
super(props);
//create the ref for the overlay
this.overlayRef = React.createRef();
this.state = {
isShowing: true
};
}
getTooltip = () => {
return <Tooltip id="tooltip">this is tooltip text</Tooltip>;
};
componentDidMount() {
//using ref to show the tooltip in the overlay
this.overlayRef.current.show();
setTimeout(() => {
//using ref to hide the tooltip in the overlay after 4 seconds
this.overlayRef.current.hide();
this.setState({ isShowing: false });
}, 4000);
}
render() {
console.log(this.state.isShowing);
return (
<div className="tool-tip-div">
<OverlayTrigger
ref={this.overlayRef}
trigger={["hover", "focus"]}
placement="top"
overlay={this.getTooltip()}
defaultShow={this.state.isShowing}
>
<Button>Click me!</Button>
</OverlayTrigger>
</div>
);
}
}
export default App;
I`m not work with react, but hope it should help you
constructor(props) {
super(props);
this.state = {
isShowing: true,
showDelayPassed: false,
showDelay: 4000
};
}
componentDidMount() {
setTimeout(
function () {
this.setState({ showDelayPassed: true });
}.bind(this),
this.state.showDelay);
}
{ this.state.isShowing ?
<Tooltip
defaultShow={false}
id="tooltip"
onMouseEnter={() => {
if(this.state.showDelayPassed) {
this.setState({ isShowing: false })
}
}}
>
this is test tooltip text
</Tooltip> : null
}
I have a React Native application and I need to call a function in HomeScreen definition to do something with it's elements. This action should be done by custom widget that is stored outside HomeScreen. I try to call the function from the widget's props, but it returns undefined. So, how can I propperly do this?
import React, { useState, useEffect, Component } from 'react';
import { Image, StyleSheet, Text, View, Button, Modal } from 'react-native';
import { LongPressGestureHandler } from 'react-native-gesture-handler';
export default function HomeScreen() {
const doSomething = () => {
console.log("Works");
}
return (
<View style={{padding: 30}}>
<LongPress
action={() => {doSomething()}}
>
<View>
<Text>Long press me</Text>
</View>
</LongPress>
</View>
);
};
function LongPress({children}, props) {
return (
<LongPressGestureHandler
onHandlerStateChange={() => {HomeScreen.action}}
minDurationMs={700}
>
<View>{children}</View>
</LongPressGestureHandler>
)
};
In your example you pass an action prop to your LongPress component. Assuming that's the function you need to fire, the following should suffice:
function LongPress({action, children}) {
return (
<LongPressGestureHandler
onHandlerStateChange={action}
minDurationMs={700}
>
<View>{children}</View>
</LongPressGestureHandler>
)
};
You can use PubSub.
class DownloadManager{
public static pointer;
async download() {
//download code
//when download update
PubSub.publish('download-complete', {status:true});
}
}
class BackupPage extends React.Component<any, any> {
componentDidMount() {
PubSub.subscribe('download-complete', (msg, data) => {
this.setState({ status :data.status})
})
}
render() {
//render code
}
}
I am trying to pass state globally using redux. What I want to do is, in the first screen, I generate a randomNumber and set that to global state.
Then, I navigate to the next screen, and when I toggle a button, I call back the global state randomNumber. Below is my code:
App.js
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { createDrawerNavigator, createStackNavigator, } from 'react-navigation'
const initialState = {randomNumber:''}
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'UPDATE':
return { randomNumber: state.randomNumber}
}
return state
}
const store = createStore(reducer)
class App extends Component {
render(){
return(
<Provider store={store}>
<View style={{flex:1,backgroundColor:'transparent'}}>
<AppDrawerNavigator/>
</View>
</Provider>
)
}
}
FirstScreen.js
This is where I generate random number and pass the state globally.
import { LoginButton, AccessToken } from 'react-native-fbsdk';
import {connect} from 'react-redux'
class FirstScreen extends Component{
GenerateRandomNumber = () => {
var RandomNumber = Math.floor(Math.random() * 100) + 1 ;
this.setState({ RandomNumber : RandomNumber },
() => console.log(this.state.RandomNumber))
}
render() {
return(
<View>
<Text>{this.state.RandomNumber}</Text>
<Button title="Generate Random Number" onPress={this.GenerateRandomNumber} />
</View>
function mapStateToProps(state) {
return {
randomNumber: state.randomNumber
}
}
export default connect(mapStateToProps, null)(FirstScreen)
SecondScreen.js
Here when I try to call back the global state randomNumber I get undefined.
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
Button
} from "react-native";
import {connect} from 'react-redux'
class SecondScreen extends Component {
render() {
return (
<View>
<Button
title="Get global State"
onPress={() => this.props.globalState()}/>
<Text>{this.props.randomNumber}</Text>
</View>
);
}
}
function mapStateToProps(state) {
return {
randomNumber: state.randomNumber
}
}
function mapDispatchToProps(dispatch) {
return {
globalState: () => dispatch({ type: 'UPDATE' }),
}
}
export default connect(mapStateToProps, null)(SecondScreen)
My question: In the secondScreen I want to call the global state randomNumber however, I am getting undefined.
Any Idea what I am doing wrong? I am very new to redux, so any advise or comments would be really appreciated! Thanks in advance!
I think in your first screen
you have
function mapStateToProps(state) {
return {
randomNumber: state.randomNumber
}
}
but while setting state you are using
this.setState({ RandomNumber : RandomNumber }
i think it should be
this.setState({ randomNumber: RandomNumber }
Also may be you skipped to dispatch action in firstscreen to set the global state. Using just this.setState you are setting the local state of component. To set global state , you have to dispatch the action .
I'm not sure how to describe what I'm trying to do with words so please take a look at the following code:
This is what causing me issues: this.fetchMessages()
import React, { Component } from 'react';
import { PushNotificationIOS, FlatList, TextInput, ActivityIndicator, ListView, Text, View, Image, TouchableWithoutFeedback, AsyncStorage } from 'react-native';
import { Actions } from 'react-native-router-flux';
import ConversationsItem from './ConversationsItem';
import { conversationFetch } from '../actions';
import { connect } from 'react-redux';
import { Divider } from 'react-native-elements'
import PushNotification from 'react-native-push-notification';
class Conversations extends Component {
componentDidMount() {
this.props.conversationFetch()
}
fetchMessages() {
this.props.conversationFetch()
}
render() {
PushNotification.configure({
onNotification: function(notification) {
PushNotification.getApplicationIconBadgeNumber((response) => {
PushNotification.setApplicationIconBadgeNumber(response + 1)
})
console.log( 'NOTIFICATION:', notification )
notification.finish(PushNotificationIOS.FetchResult.NoData);
this.fetchMessages()
}
});
if (!this.props.email) {
return (
<View style={{flex: 1, paddingTop: 20}}>
<ActivityIndicator />
</View>
);
}
console.log(this.props.conversations)
return (
<View style={{flex: 1, backgroundColor: 'white'}}>
...
</View>
);
}
}
const mapStateToProps = (state) => {
console.log(state)
const { conversations } = state.conversation;
const { email } = state.conversation;
return { conversations, email };
};
export default connect(mapStateToProps, { conversationFetch })(Conversations);
When I call this.fetchMessages() inside PushNotification.configure({}), I get the following error message:
this.fetchMessages is not a function
I'm not sure if what I'm doing is possible but if so I'd really like to know how to make this work.
I tried adding .bind(this) and other ways around but got same error anyways.
Thanks for you help.
Functions declared with function keyword has their own this, so this inside onNotification function does not refer to the class.
Therefore use arrow function syntax, which will lexically resolve this and value of this inside will refer to class itself. So convert
onNotification: function(notification) {
to
onNotification: (notification) => {
So you have in fact tried binding the fetchMessages function in the constructor? Like such:
constructor(props) {
super(props)
this.fetchMessages = this.fetchMessages.bind(this);
}
You can also use an arrow function to bind your method to the class without calling the constructor like such:
() => this.fetchMessages()
I don't understand how I'm getting this error (pic below). In my LoginForm.js file, the onEmailChange(text) is giving me an unresolved function or method call to onEmailChange() error when I hover over it in my WebStorm IDE. In my index.js file, no error is being thrown anywhere.
I've looked around SO for this issue but it doesn't fully pertain to my problem.
I've tried File > Invalidate Caches/Restart but that didn't work.
Here's App.js:
import React, { Component } from 'react';
import {StyleSheet} from 'react-native';
import {Provider} from 'react-redux';
import {createStore} from 'redux';
import firebase from 'firebase';
import reducers from './reducers';
import LoginForm from './components/common/LoginForm';
class App extends Component {
render() {
return(
<Provider style={styles.c} store={createStore(reducers)}>
<LoginForm/>
</Provider>
);
}
}
const styles = StyleSheet.create({
c: {
flex: 1
}
});
export default App;
Here's LoginForm.js:
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {emailChanged} from 'TorusTeensApp/src/actions';
import {Text, StyleSheet, KeyboardAvoidingView, TextInput, TouchableOpacity} from 'react-native';
class LoginForm extends Component {
render() {
onEmailChange(text)
{
this.props.emailChanged(text);
}
return(
<KeyboardAvoidingView style={styles.container}>
<TextInput
style={styles.userInput}
onsubmitediting={() => this.passwordInput.focus()}
returnKeyType={"next"}
placeholder={"Email"}
label={"Email"}
keyboardType={"email-address"}
autoCorrect={false}
onChangeText={this.onEmailChange.bind(this)}
value={this.props.email}
/>
<TextInput
style={styles.userInput}
ref={(userInput) => this.passwordInput = userInput}
returnKeyType={"go"}
placeholder={"Password"}
label={"Password"}
secureTextEntry
/>
<TouchableOpacity style={styles.buttonContainer}>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.buttonContainer}>
<Text style={styles.buttonText}>Create Account</Text>
</TouchableOpacity>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
padding: 20 // creates a gap from the bottom
},
userInput: {
marginBottom: 20,
backgroundColor: '#9b42f4',
height: 40
},
buttonContainer: {
backgroundColor: '#41bbf4',
paddingVertical: 10,
marginBottom: 20
},
buttonText: {
textAlign: 'center',
color: '#FFFFFF'
}
});
const mapStateToProps = state => {
return {
email: state.auth.email
};
};
export default connect(mapStateToProps, null, {emailChanged}) (LoginForm);
Here's index.js:
import {EMAIL_CHANGED} from './types';
export const emailChanged = (text) => {
return {
type: 'EMAIL_CHANGED',
payload: text
};
};
export default emailChanged();
Your connect is miswired
connect(mapStateToProps, null, {emailChanged}) (LoginForm);
It should be something like:
connect(mapStateToProps,
(dispatch) => ({emailChanged: (text) => dispatch(emailChanged(text))})
)(LoginForm);
so that your action actually gets dispatched
and as spotted by emed in comment:
export default emailChanged;
without parentheses.
You defined your callback inside your render() method and not inside the class body. Do it like this:
class LoginForm extends Component {
onEmailChange(text) {
this.props.emailChanged(text);
}
render() {
return(...);
}
}
Also you shouldn't bind methods inside your render() method. Do it in the constructor of your Component:
class LoginForm extends Component {
constructor(props) {
super(props);
this.onEmailChange.bind(this);
}
onEmailChange(text) {
// do something
}
// other methods
}
Or if you use babel and ES6, you can define your callback with an arrow function, then it will be automatically bound:
class LoginForm extends Component {
onEmailChange = text => {
// do something
};
// other methods
}
See also the react docs about autobinding.
Also your call to connect seems incorrect. If you want to dispatch the action emailChanged it has to look like this:
const mapStateToProps = state => {
return {
email: state.auth.email
};
};
const mapDispatchToProps = dispatch => {
// this put a function emailChanged into your props that will dispatch the correct action
emailChanged: text => dispatch(emailChanged(text))
};
const LoginFormContainer = connect(mapStateToProps, mapDispatchToProps)(LoginForm);
export default LoginFormContainer;
The third argument to connect needs to be a function that knows how to merge the output of mapStateToProps, mapDispatchToProps, and ownProps all into one object that is then used as props for your connected component. I think you're trying to pass that action to the mapDispatchToProps argument, which is the second argument not the third. So, based on what I think you're doing, you probably wanna change your connect line to look like this.
export default connect(mapStateToProps, {emailChanged}) (LoginForm);
Then, export the function from your actions file not the output of calling that function.
export default emailChanged;
Notice I removed the parentheses so it's not being called.
Then make the callback function a method on your class and bind it in the constructor.
constuctor(props) {
super(props);
this.onEmailChange = this.onEmailChange.bind(this);
}
onEmailChange(text) {
this.props.emailChanged(text);
}
Then update onChangeText on that element.
onChangeText={this.onEmailChange}