React Native function not triggering - reactjs

So, I have this component,
{ this.props.isConfirmModalOpen && shiftInvite && <ConfirmApplicationPopUp
memberPhoto={props.memberProfile && props.memberProfile.photo}
venueLogo={getOr('noop', 'account.logo', shiftInvite)}
isOpen={props.isConfirmModalOpen}
shift={shiftInvite}
isOnboarding={isOnboardingMember}
onClose={props.onToggleConfirmPopUp}
onConfirm={this.handleConfirmApplication}
checkValues={props.confirmationCheckValues}
onUpdateCheckValues={props.onUpdateConfirmationCheckValues}
isHomeComponent
/> }
As you can see, I pass on onConfirm the handleConfirmApplication function, which is a check for some stuff and has to run a function in the try block, , here's the function
handleConfirmApplication = async () => {
const checkVals =
get('shift.account.accountName', this.props) === ONBOARDING_ACCOUNT
? omit('payRate', this.props.confirmationCheckValues)
: this.props.confirmationCheckValues;
if (Object.values(checkVals).every(val => val)) {
this.props.onToggleConfirmPopUp();
this.props.onToggleLoadingApply();
try {
console.log('inTry1');
await this.handleShiftInviteDecision('ACCEPT');
console.log('inTry2');
} catch (e) {
Alert.alert('Error', parseError(e));
} finally {
this.props.onToggleLoadingApply();
console.log('inFinally');
}
} else {
Alert.alert('Error', 'Please confirm all shift requirements');
}
};
My problem is, for whatever reason, it doesn't run the handleShiftInviteDecision('ACCEPT) for whatever reason, i'm awaiting it, tried to put it in another function, call them both from another function ETC, the function does not run!
Here's the handleShiftInviteDecision function too
handleShiftInviteDecision = (decision: 'ACCEPT' | 'DECLINE') => async () => {
console.log('handleSIDecision1');
const [shiftInvite] = getOr([], 'shiftInvites', this.state.modals);
console.log('handleSIDecision2');
if (decision === 'ACCEPT') {
analytics.hit(new PageHit(`ShiftInviteModal-ACCEPT-${shiftInvite.id}`));
console.log('handleSIDecision3');
} else if (decision === 'DECLINE') {
analytics.hit(new PageHit(`ShiftInviteModal-DECLINE-${shiftInvite.id}`));
console.log('handleSIDecision4');
}
try {
console.log("thisSHouldRun")
this.setState({ isLoading: true, display: false });
await this.props.updateMyApplication(shiftInvite.id, decision);
console.log('handleSIDecision5');
} catch (e) {
Alert.alert('Error', parseError(e));
} finally {
this.setState({ isLoading: false, display: false });
}
};
Any ideeas on what I could do?

The function handleShiftInviteDecision is a function that returns an async function.
handleShiftInviteDecision = (decision: 'ACCEPT' | 'DECLINE') => async () => {
So, you would need to call the async function it returns to invoke it:
try {
console.log('inTry1');
await this.handleShiftInviteDecision('ACCEPT')(); // <--- here
console.log('inTry2');
} catch (e) {

Related

AsyncStorage doesn't save data but no error

Now I am aware that there are many of questions that asked the same thing. But I also found many that implemented the right methods but nothing worked for them even peoples' answers
Basically, I wanted to use AsyncStorage to save a few user preferences. At first everything worked and was saved correctly, but then suddenly nothing worked anymore.
I kept trying and trying, and made a very interesting finding.
First here's my code:
My import:
import AsyncStorage from '#react-native-async-storage/async-storage';
Default State:
state : AppState = {
messages: [],
isMuted: false
}
This is my getter. It works on init:
componentDidMount() {
this.getSettings();
}
async getSettings() {
try {
AsyncStorage.getItem("muted").then((muted)=> {
if (muted != null) {
this.setState({"isMuted": eval(muted)});
console.log("init! "+this.state.isMuted.toString());
} else {
console.log("init! found null");
}
})
} catch(e) {
// error reading value
}
}
Here's my setter, it works onPress of a button
onPressSpeaker = async () => {
var muted = !this.state.isMuted;
this.setState({"isMuted": muted});
try {
await AsyncStorage.setItem("muted", this.state.isMuted.toString());
console.log("saved! "+this.state.isMuted.toString());
const muted = await AsyncStorage.getItem('muted');
if(muted !== null) {
console.log("data found! "+this.state.isMuted.toString());
}
} catch (e) {
console.log("error")
}
};
I believe I set everything correctly.
But here's my log (from Flipper)
20:57:41.654
init! true
20:57:44.247
saved! false
20:57:44.256
data found! false
20:58:04.788
Running "Voice Message" with {"rootTag":51}
20:58:05.800
init! true
The last init was supposed to return the new value but it keeps returning the old value again and again, everytime I refresh (restart) the application.
Did I do something wrong? Am I missing something? Is there something I need to know about react-native-async-storage?
I think the problem that you are storing the this.state.isMuted value before the state mutates
To better understand you can try this code
onPressSpeaker = async () => {
var muted = !this.state.isMuted;
this.setState({"isMuted": muted});
try {
//Here we are trying to log the state before Add it to Storage
console.log('State => Before AsyncStorage.setItem', this.state.isMuted)
await AsyncStorage.setItem("muted", this.state.isMuted.toString());
console.log("saved! "+this.state.isMuted.toString());
const muted = await AsyncStorage.getItem('muted');
if(muted !== null) {
console.log("data found! "+this.state.isMuted.toString());
}
} catch (e) {
console.log("error")
}
};
Your log will now be like this
20:57:41.654
init! true
20:57:44.247
'State => Before AsyncStorage.setItem' true
20:57:44.247
saved! false
20:57:44.256
data found! false
Solution: So you need to write the function in the callback to the setState function
storeIsMuted = async () => {
try {
console.log("before setItem", this.state.isMuted.toString());
await AsyncStorage.setItem("muted", this.state.isMuted.toString());
console.log("saved! " + this.state.isMuted.toString());
//
const muted = await AsyncStorage.getItem("muted");
if (muted !== null) {
console.log("data found! " + this.state.isMuted.toString());
}
} catch (e) {
console.log("error");
}
};
onPressSpeaker = () => {
var muted = !this.state.isMuted
this.setState({ isMuted: muted }, async () => this.storeMuted());
};
Documentation
SetState

Why is not the state updated?

I have a function that updates a state with a change and adds a value, but the state in the 'addResponse' function does not always change:
handleSelected (e, item) {
this.setState({
current_component_id: item.id,
}, () => this.addResponse()
);
};
Call function above:
addResponse (e) {
const { enrollment_id, evaluation_id, user_id, question_id, current_component_id,
responses, current_question, current_question_id
} = this.state;
console.log(current_component_id)
if (current_component_id != 0) {
const newResponse = {
enrollment_id: enrollment_id,
evaluation_id: evaluation_id,
user_id: user_id,
question_id: current_question_id,
answer_component: current_component_id,
};
function hasAnswer(res) {
const list_question_id = res.map((item) => {
return item.question_id
});
if (list_question_id.includes(current_question_id)) {
return true
} else {
return false
}
}
if (responses === undefined) {
this.setState({
responses: [newResponse]
}
, () => console.log('---------> primeiro', this.state.responses)
)
} else {
const check = hasAnswer(responses);
if (check) {
this.setState(prevState => {
prevState.responses.map((item, j) => {
if (item.question_id === current_question_id) {
return item.answer_component = current_component_id
}
return item ;
})
}
, () => { console.log('----> questao alterada ', this.state.responses)}
)
} else {
this.setState({
responses: [...this.state.responses, newResponse]
}
, () => console.log('------> questao nova', this.state.responses)
);
}
}
}
// this.nextQuestion();
};
the first console.log is always correct, but the others do not always change, I know that setState is asyn, but I thought that as I call the addResponse function it would be async
There is a problem in your how you call setState when check is true.
It should be
this.setState(prevState => ({
responses: prevState.responses.map((item, j) => {
if (item.question_id === current_question_id) {
item.answer_component = current_component_id
}
return item ;
})
})
, () => { console.log('----> questao alterada ', this.state.responses)}
)

Undefined function when importing it from different file?

So, I have this component
<ConfirmApplicationPopUp
onConfirm={() => handleConfirmApplication(true)}
/>
whenever i try to run the function[it's passed to the props of ConfirmApplicationPopUp component as you can see] it tells me that it's undefined
my function is in another file
I import it like this
import handleConfirmApplication from '../shift-details/utils';
the function itself is
export const handleConfirmApplication = async (isInvite) => {
const checkVals =
get(`shift${isInvite ? 'Invite' : ''}.account.accountName`, this.props) === ONBOARDING_ACCOUNT
? omit('payRate', this.props.confirmationCheckValues)
: this.props.confirmationCheckValues;
if (Object.values(checkVals).every(val => val)) {
this.props.onToggleConfirmPopUp();
this.props.onToggleLoadingApply();
try {
if(isInvite) {
await this.handleShiftInviteDecision('ACCEPT')();
}
else {
const shiftId = this.props.shift.id;
const {
data: { updatedShifts },
} = await this.props.updateMyApplication(shiftId, 'APPLY');
this.setState({
updatedShift: updatedShifts.find(({ id }) => id === shiftId),
});
}
} catch (e) {
Alert.alert('Error', parseError(e));
} finally {
this.props.onToggleLoadingApply();
}
} else {
Alert.alert('Error', 'Please confirm all shift requirements');
}
}
Any ideeas why that happens? I have checked some of the other topics about this but with no avail :(
It's because you are not exporting the function as default.
If you import it in the following way it should work.
import { handleConfirmApplication } from '../shift-details/utils';

How can I put this function into a component?

I have a react native codebase in which I import a component and use the same function twice but with slight differences. I would like to outsource it into a new component somehow. Any ideas?
It looks like this :
handleConfirmApplication = async () => {
const checkVals =
get('shiftInvite.account.accountName', this.props) === ONBOARDING_ACCOUNT
? omit('payRate', this.props.confirmationCheckValues)
: this.props.confirmationCheckValues;
if (Object.values(checkVals).every(val => val)) {
this.props.onToggleConfirmPopUp();
this.props.onToggleLoadingApply();
try {
await this.handleShiftInviteDecision('ACCEPT')();
} catch (e) {
Alert.alert('Error', parseError(e));
} finally {
this.props.onToggleLoadingApply();
}
} else {
Alert.alert('Error', 'Please confirm all shift requirements');
}
};
And the second one is the following :
handleConfirmApplication = async () => {
const checkVals =
get('shift.account.accountName', this.props) === ONBOARDING_ACCOUNT
? omit('payRate', this.props.confirmationCheckValues)
: this.props.confirmationCheckValues;
if (Object.values(checkVals).every(val => val)) {
this.props.onToggleConfirmPopUp();
this.props.onToggleLoadingApply();
try {
const shiftId = this.props.shift.id;
const {
data: { updatedShifts },
} = await this.props.updateMyApplication(shiftId, 'APPLY');
this.setState({
updatedShift: updatedShifts.find(({ id }) => id === shiftId),
});
} catch (e) {
Alert.alert('Error', parseError(e));
} finally {
this.props.onToggleLoadingApply();
}
} else {
Alert.alert('Error', 'Please confirm all shift requirements');
}
};
Simply use an if/else statement in your try/catch and a ternary condition to create your string. Choosing between one or another should be done by passing a parameter to your function :
handleConfirmApplication = async (isInvite) => {
const checkVals =
get(`shift${isInvite ? 'Invite' : ''}.account.accountName`, this.props) === ONBOARDING_ACCOUNT
? omit('payRate', this.props.confirmationCheckValues)
: this.props.confirmationCheckValues;
if (Object.values(checkVals).every(val => val)) {
this.props.onToggleConfirmPopUp();
this.props.onToggleLoadingApply();
try {
if(isInvite){
await this.handleShiftInviteDecision('ACCEPT')();
}
else{
const shiftId = this.props.shift.id;
const {
data: { updatedShifts },
} = await this.props.updateMyApplication(shiftId, 'APPLY');
this.setState({
updatedShift: updatedShifts.find(({ id }) => id === shiftId),
});
}
} catch (e) {
Alert.alert('Error', parseError(e));
} finally {
this.props.onToggleLoadingApply();
}
} else {
Alert.alert('Error', 'Please confirm all shift requirements');
}
};
And calling it :
handleConfirmApplication(true)
Have I missed any other differences between your functions ?
To Use it in a reusable component :
handleConfirmApplication = async () => {
const { isInvite } = this.props
const checkVals =
And calling it :
<MyComponent isInvite={false} /> //Just switch it to true to get the other version

Execute method after getting response from $http.get

I want to add a profile if it doesn't exist, otherwise, I will only do an update:
profileExists(id) {
return this.$http.get('/profiles/' + id).then(response => {
return response.data;
});
}
submitProfile(profile) {
if (!this.profileExists(profile.id)) {
this.addProfile(profile);
} else {
this.updateProfile(profile);
}
}
addProfile(profile) {
return this.$http.post('/profiles', profile)
.then(res => res.data)
.catch(this.$http.fallback);
}
updateProfile(profile) {
return this.$http.put('/profiles/' + profile.id)
.then(res => res.data)
.catch(this.$http.fallback);
}
The problem with this code is that in the submitProfile method, this.addProfile(profile); is executed before the return statement of profileExists(id)... I have a hard time manipulating asynchronous code. I don't know how to execute the code after finishing all the profileExists(id) method.
And my second question is why do we put a return statement on this.$http.get or this.$http.put?
Thanks.
I think's you need to call your addProfile() in success callback from your profileExists()
Try this.
profileExists(id) {
return this.$http.get('/profiles/' + id).then(response => {
if(!response.data){
this.addProfile(profile);
}else{
this.updateProfile(profile);
}
});
}
Or
profileExists(id){
return this.$http.get('/profiles/' + id);
}
submitProfile(profile) {
this.profileExists(profile.id).then(response => {
if (!response.data) {
this.addProfile(profile);
} else {
this.updateProfile(profile);
}
})
}
By the time your code reaches the if clause, profileExists has not returned, so it evaluates to false. You can change your code to check in the callback function
submitProfile(profile) {
this.profileExists(profile.id)
.then(response => {
if(!response.data){
this.addProfile(profile);
} else {
this.updateProfile(profile);
}
})
}
You can do it this way:
submitProfile(profile) {
return this.profileExists(profile.id)
.then(exists => {
if(!exists){
return this.addProfile(profile);
} else {
return this.updateProfile(profile);
}
})
}
We put return before the actual call because we want to return the promise . So whomever is calling submitProfile can perform some action after this action is performed. Like this :
service.submitProfile(profile)
.then(result => console.log('submit success'));
Also they can catch errors wherever it happened in all the code above in single place.
service.submitProfile(profile)
.then(result => console.log('submit success'))
.catch(err => console.error('Failed to submit',err);
You need to set async http true. Try adding this line of code in your config.
$httpProvider.useApplyAsync(true);

Resources