EDITED: I want to store a timestamp when the react native app goes into the background, to see if re-login is needed. I use the async storage to save the timestamp on the device, with help of the appstate functionality.
But the getItem and setItem code never executes. any idea why ?
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}
_handleAppStateChange = (nextAppState: any) => {
if (
this.state.appState.match(/inactive|background/) &&
nextAppState === 'active'
) {
this.getTime();
this.checkTimeStamp();
console.log(this.state.time, 'time var');
console.log('app is active, and has been in the background');
} else if (
this.state.appState == 'active' &&
nextAppState == 'active'
) {
this.setTime();
this.checkTimeStamp();
console.log(this.state.time, 'time var');
console.log('app is active, and just opened.');
} else {
this.setTime()
//sets the timestamp
console.log('app in background or closed');
}
this.setState({ appState: nextAppState });
};
async setTime() {
let seconds = this.generateTime();
try {
const val = await AsyncStorage.setItem('time', seconds.toString());
this.setState({ time: Number(val) });
} catch (error) {
console.error('onRejected function called: ' + error);
}
}
async getTime() {
let please = await AsyncStorage.getItem('time');
this.setState({ time: Number(please) });
console.log(this.state.time, 'time var');
}
Take a look at AppState https://facebook.github.io/react-native/docs/appstate
It allows you to listen for "active"/"background" state changes.
Related
I created a function that fetches cart items from the API
There are 2 API one is for authenticated users and the other is for non-authenticated users
But the execution of the non-authenticated users takes more time to get data that's why it even overwrites the data for the authenticated user
So how can I solve this problem
Inside the context
usestate to call the cart function
useEffect(() => {
console.log("the value of user", userAuthenticated);
if (userAuthenticated == true) {
cartdataupdater("useEffect");
} else {
cartdataupdater("useEffect withou");
}
}, [userAuthenticated]);
cart updater
const cartdataupdater = (from = "this") => {
console.log(" worken", userAuthenticated, from);
var startTime = performance.now();
if (userAuthenticated == true) {
axios.get(`http://127.0.0.1:8000/core/cart/1/`).then((response) => {
setcartData(response.data);
console.log("the end is not good");
var endTime = performance.now();
console.log(
`Call to doSomething took ${
endTime - startTime
} milliseconds`
);
});
} else {
console.log("not authenticated");
var startTime = performance.now();
axios
.get(
`http://127.0.0.1:8000/core/dcart/${localStorage.getItem(
"cart_id"
)}`
)
.then((response) => {
setcartData(response.data);
console.log("the end");
console.log(from);
var endTime = performance.now();
console.log(
`Call to doSomething took ${
endTime - startTime
} milliseconds`
);
});
}
};
Thanks in advance
I anything is required I will provide you
I founded the soltion
I solve it by adding the loading state which helps me to stop the extra request
const cartdataupdater = () => {
if (userAuthenticated == true) {
axios.get(`http://127.0.0.1:8000/core/cart/1/`).then((response) => {
setcartData(response.data);
});
} else {
try {
axios
.get(
`http://127.0.0.1:8000/core/dcart/${localStorage.getItem(
"cart_id"
)}`
)
.then((response) => {
setcartData(response.data);
});
} catch (error) {
console.log(error);
}
}
};
useEffect(() => {
if (userauthloading == false) {
cartdataupdater();
}
}, [userauthloading, userAuthenticated]);
I use setInterval() to send GET request for state updating. I also use clearInterval() after the update process complete.
//
// getSynProcessState used for updating data by sending GET request to an API after every minute
//
intervalID = 0;
getSynProcessState = () => {
// get total and current sync
this.intervalID = setInterval(() => {
axios.get('http://mySite/data/')
.then(res => {
console.log(res.data)
});
},1000);
}
//
// clearInterval() will run if this.state.isSyncStart === false
//
componentDidUpdate() {
if (this.state.isSyncStart) {
this.getSynProcessState() //setInterval()
console.log('componentDidUpdate: ' + this.state.isSyncStart)
} else {
clearInterval(this.intervalID)
console.log('componentDidUpdate: ' + this.state.isSyncStart)
}
}
As you can see that when [this.state.isSyncStart === true] => setInterval() run OK
But when [this.state.isSyncStart === false] => clearInterval() run but the GET requests keep sending
You are overwriting the current interval in your componentDidUpdate call. Do a check e.g.
if (this.state.isSyncStart) {
this.interValID == 0 && this.getSynProcessState() //setInterval()
console.log('componentDidUpdate: ' + this.state.isSyncStart)
} else {
clearInterval(this.intervalID)
console.log('componentDidUpdate: ' + this.state.isSyncStart)
}
I somehow solved the problem by adding runOnce and set it in the 'If' Condition. Maybe it prevent the overwriting on [this.intervalID]
runOnce = true
getSynProcessState = () => {
if (this.state.isSyncStart && this.runOnce) {
this.runOnce = false
this.intervalID = setInterval(() => {
axios.get('http://192.168.51.28:8031/process/')
.then(res => {
console.log(res.data)
// this.setState({
// total: res.data.total,
// current: res.data.current
// })
// console.log('1: ' +this.state.total)
});
},200);
} else {
clearInterval(this.intervalID)
}
}
componentDidUpdate() {
this.getSynProcessState()
}
I'm emitting socket event from my sever end point & listen that event on react.js client with socket.on() but i found my socket.on event firing multiple times when emit event.I read many question related this issue on stack overflow but did't succeed.
Here relavant code:
server
currentUsers: async function (req, res, next) {
try {
let io = req.app.get("socketio") // get socketio instance
const uoid = req.body.uoid;
const uuid = req.body.uuid || req.decoded.uuid
const beacon_name = req.body.beacon_name
if (uuid !== undefined && beacon_name !== undefined && uoid !== undefined) {
let find = await knex('current_users').where(knex.raw('uuid = ? and uoid = ?', [uuid, uoid])).catch((err) => { return Promise.reject(err) })
if (find.length == 0) {
let result = await knex('current_users').insert({ uuid: uuid, uoid: req.body.uoid, beacon_name: beacon_name, created_at: helper.currentTimeStamp(), in_at: helper.currentTimeStamp(), in: 1,out: 0 }).catch((err) => { return Promise.reject(err) })
console.log('result', result)
let getResult = await knex('users').select('users.id', 'users.name', 'users.email','users.mobile_number', 'users.auth_type', 'users.uuid', 'users.role','current_users.beacon_name','current_users.id as ob_id','beacons_info.beacon_room','current_users.in_at','current_users.out_at').innerJoin('current_users', 'users.uuid', '=', 'current_users.uuid').innerJoin('outlets','outlets.id','=','current_users.uoid').innerJoin('beacons_info', 'beacons_info.name', '=', 'current_users.beacon_name').where(knex.raw('current_users.id = ?',result))
io.emit('in_users',getResult)
res.end()
}
}
} catch (err) {
console.log("err =====>", err)
}
}
client
import React from "react";
import socket from "../../../../utils/socket.io"; // get socket
import EventEmitter from 'events';
class CurrentUsers extends React.Component {
_isMounted = false;
constructor(props) {
super(props);
this.outlet_id = sessionStorage.outlet_id ? sessionStorage.outlet_id : "";
this.selecteId = null;
this.in_users = [];
this.state = {
loading: true,
data: [],
editData: {
name: "",
date: "",
room: ""
}
};
}
componentDidMount() {
console.log("calling component did mount");
this._isMounted = true;
this.setState({ loading: true });
socket.emit('request-current-users-list',this.outlet_id)
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
socket.on('get-current-users-list',(data)=>{
this.setState({ data: data,loading: false})
})
console.log(EventEmitter.listenerCount(socket, 'in_users'));
socket.on('in_users', (data) => {
console.log("=== in ===", data)
})
return (
// template html code
);
}
}
here socket.on(in_users) event firing multiple times.
Put all of your socketio listerners in React inside componentDidMount ,
Its because re-renders, React re-renders multiple times when ever any state changes ,so basically your socketio listerers just keep adding up. That is why you are getting multiple events fired. You just need to add your socketio listeners once , so add your listeners inside componentDidMount()
Somehow it keeps adding the listener each time the socket.on is fired. I tried this:
socket.off('MY_EVENT').on('MY_EVENT', () => doThisOnlyOnce());
I found it on code grepper, and it worked for me.
EDIT:
socket.on is fired on each render. so turning it off and on isn't such an efficient way of doing it. A better way would do it would be to run socket.on on first render.
useEffect(()=>{
socket.on('MY_EVENT', () => doThisOnlyOnce());
},[])
I am trying to build a water reminder app. I have 3 screens and I am using react-navigation
Home (that I allow users to increase their amount drink that day and display how much water they drunk)
Notifications (where users defining with switch buttons if they want
to receive notifications and when to receive)
Settings (where the user enters age, weight to determine how much they
should drink daily). this is the first screen users see when they
downloaded the app
I am setting the drunk value to zero after every day with a check date function. My problem is drunk value is not automatically set to zero after loading the app. Rest of the values such as progress are set to zero but not drunk value. When I change one screen and come back to the Home screen, it is set to zero.
state = {
progress: 0,
drunk: 0,
open: false,
goal: 0,
};
componentDidMount() {
this.willFocusSubscription = this.props.navigation.addListener('willFocus', payload => {
// perform check when the component mounts
this.checkDate();
// retrieve data from AsyncStorage
this._retrieveData();
});
}
// function to retreive data from AsyncStorage
_retrieveData = async () => {
try {
const sliderValue = await AsyncStorage.getItem('sliderValue');
const drunk = await AsyncStorage.getItem('drunk');
const progress = await AsyncStorage.getItem('progress');
if (sliderValue !== null) {
// We have data!! ve stateleri belirledik
this.setState({ goal: parseInt(sliderValue) });
} else if (sliderValue === null) {
this.setState({ goal: 0 });
}
if (drunk !== null) {
this.setState({ drunk: parseInt(drunk) });
} else if (drunk === null) {
this.setState({ drunk: 0 });
}
if (progress !== null) {
this.setState({ progress: parseFloat(progress) });
} else if (progress === null) {
this.setState({ progress: 0 });
}
} catch (error) {
console.log(error.message);
}
};
// function to check date and set drunk to zero
checkDate = async () => {
// create a string with the current date
let currentDateString = moment().format('DDMMYYYY');
// get the value from storage
let savedDateString = await AsyncStorage.getItem('storedDate');
// create variables for differences on year month
let yearDiff = currentDateString.slice(4) - savedDateString.slice(4)
let monthDiff = currentDateString.slice(2, 4) - savedDateString.slice(2, 4)
let dayDiff = currentDateString.slice(0, 2) - savedDateString.slice(0, 2)
// if there is a value on AsyncStorage
if (savedDateString) {
// if difference is bigger than zero set drunk and progress to zero
if (yearDiff > 0 || monthDiff > 0 || dayDiff > 0) {
// this is where you put the code that resets everything
// clear the values that you have previously saved
// remember to save the new date
this.setState({ drunk: 0, progress: 0 }, () => {
this._storeData();
});
try {
await AsyncStorage.setItem('storedDate', currentDateString);
} catch (err) {
console.debug(err.message);
}
}
} else {
// save the time as this is the first time the app has launched
// do any other initial setup here
try {
await AsyncStorage.setItem('storedDate', currentDateString);
} catch (err) {
console.debug(err.message);
}
}
};
render() {
return (
<Provider>
<View style={styles.container}>
<Text style={styles.drunk}>
{this.state.drunk.toFixed(0)} / <Text style={styles.goal}>{this.state.goal}</Text>
</Text>
</View>
</Provider>
)
}
Problem I was encountering that I am calling AsyncStorage method inside navigation listener. Since AsyncStorage is working asynchronously,AsyncStorage methods are not completed inside navigation listener.
How I did solve this issue is that I made componentDidMount async function and call methods outside of navigation listener with await.
async componentDidMount() {
// perform check when the component mounts
await this.checkDate();
// retrieve data from AsyncStorage
await this._retrieveData();
this.willFocusSubscription = this.props.navigation.addListener('willFocus', payload => {
// perform check when the component mounts
this.checkDate();
// retrieve data from AsyncStorage
this._retrieveData();
});
}
My React client app should guess the secret number between 1 and 10 000. Here is my code:
import axios from 'axios';
import React, { Component } from 'react';
class GuessEngine extends Component {
constructor(props) {
super(props);
this.state = {
number: null,
result: null,
};
}
componentDidMount() {
const firstGuess = 5000;
axios
.post('http://localhost:3001/number', {
isNumber: firstGuess,
})
.then(response => {
const { resultCode } = response.data;
this.setState({ number: firstGuess });
this.setState({ result: resultCode });
})
.catch(error => console.log(error));
}
componentDidUpdate(prevProps, prevState) {
if (prevState !== this.state) {
if (this.state.result === 'lower') {
const newNumber = this.state.number - 1;
axios.post('http://localhost:3001/number', {
isNumber: newNumber,
});
this.setState({ number: newNumber });
}
if (this.state.result === 'higher') {
const newNumber = this.state.number + 1;
axios.post('http://localhost:3001/number', {
isNumber: newNumber,
});
this.setState({ number: newNumber });
}
if (this.state.result === 'success') {
console.log(`Success! The secret number is ${this.state.number}!`);
}
}
}
render() {
return <div>Test</div>;
}
}
export default GuessEngine;
And I'm getting an error like this:
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
So if I can't use componentDidUpdate like this, what is the proper way to use React Lifecycle Hooks to make it work?
My app has sent 1011 request and than it crashed.
SOLUTION
So using #John_Ruddell answer I came up with this solution:
componentDidUpdate() {
if (this.state.result !== 'success') {
if (this.state.result === 'lower') {
const newNumber = this.state.number - 1;
axios
.post('http://localhost:3001/number', {
isNumber: newNumber,
})
.then(response => {
const { resultCode } = response.data;
this.setState({ result: resultCode, number: newNumber });
});
} else if (this.state.result === 'higher') {
const newNumber = this.state.number + 1;
axios
.post('http://localhost:3001/number', {
isNumber: newNumber,
})
.then(response => {
const { resultCode } = response.data;
this.setState({ result: resultCode, number: newNumber });
});
}
} else if (this.state.result === 'success') {
console.log(`Success! The secret number is ${this.state.number}!`);
} else {
console.log(`Sorry! Some errors occured!`);
}
}
This code does not compares this.state.number !== prevState.number, but only in this way I forced it to work
you are setting state every time the component did update is firing.. instead of waiting for a callback from the request to see if its lower or higher
also you should put the logic of state transitions into better conditionals
const nextNum = { lower: -1, higher: 1 } // simple mapping of the next guess so you can reduce amount of code
componentDidUpdate(prevProps, prevState) {
if (this.state.result && this.state.number !== prevState.number) {
if (nextNum[this.state.result]) {
// make request with the number
const newNumber = nextNum[this.state.result]
axios.post('http://localhost:3001/number', {
isNumber: newNumber,
}).then(response => {
const { resultCode } = response.data;
this.setState({result: resultCode, number: newNumber})
}).catch(error => console.log(error));
} else if (this.state.result === 'success') {
console.log(`Success! The secret number is ${this.state.number}!`);
}
}
}
Note the key thing here is you should only setState AFTER the request comes back.. or else you will just endlessly setState.. because this.state.result will never be updated to be success
setState will lead to the update so your componentDidUpdate will be called over and over again:
componentDidUpdate(prevProps, prevState) {
// after each update this will be true and further runing another updates
if (prevState !== this.state) {
}
}
You need better logic to decipher whether you need to do an update or not. Meaning at some point componentDidUpdate should not do anything.