setState() callback argument returned a Future flutter - mobile

When i wanted to get my token i have this error :
setState() callback argument returned a Future.
onPressed: () {
setState(() async {
if (_formKey.currentState.validate()) {
Candidate candidate = new Candidate(
lastname: lastname,
firstname: firstname,
email: email);
await candidate.candidateAuth(map: candidate.toMap());
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
ThemePage(candidate: candidate)));
}
});
},
The problem, when i continue in my app, i have more problems threading.

setState need to receive a pure function without side effects.
You can adjust that so you can call setState after the async function. Like this:
onPressed: () {
if (_formKey.currentState.validate()) {
Candidate candidate = new Candidate(
lastname: lastname,
firstname: firstname,
email: email);
await candidate.candidateAuth(map: candidate.toMap());
setState((){});
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
ThemePage(candidate: candidate)));
}
},

Related

Await not working when pass async function as params LODASH

I created a custom function with params using callback to reuse, but await not working
const _debounceSearch = debounce(
async (callback: (params: RequestParams) => any, value: string | undefined, language: string | undefined) => {
const data = await callback({ q: value, lang: language });
console.log('data on search', data);
return data;
},
300,
);
const dataCompanies = await _debounceSearch(apiSearchCompany, searchValue, languageParam);
console.log('dataCompanies', dataCompanies);
if (dataCompanies) {
setCompanySearchTags(
data.items.map((item: Company) => ({ value: item.id, label: item.name, checked: false })),
);
}
I only got undefined result although i pass await prefix.
I don't think debounce function itself can be a promise. debounce(fn) is just a regular function, but you can make a Promise whenever you want.
Maybe checkout, Using lodash debounce to return a promise

How to add async functionality to a Firebase 'put' and 'set' query operation

I have been using the following function to store a file in Firebase Storage, return the URL, which I then store along with some other fields, in Firestore.
Where do I add an 'await' or how do I add a promise so that the 'history.push("/") is not called until all operations have completed? At the moment I think it's pushing me on to the next page before it's finished.
async function handleSubmit(e) {
e.preventDefault()
const collectionRef = useFireStore.collection('users').doc(`${currentUser.uid}`);
const storageRef = useStorage.ref("avatars")
const fileRef = storageRef.child(`${uuidv4()}`)
fileRef.put(file).then(() => {
fileRef.getDownloadURL().then(function (url) {
collectionRef.set({
createdAt: timestamp(),
email: currentUser.email,
userid: currentUser.uid,
username: username,
firstname: firstname,
lastname: lastname,
avatar: url
})
});
})
history.push("/")
}
What would be some best-practices here, please?
Kind regards, Matt
You can do something like this,
async function handleSubmit(e) {
e.preventDefault()
const collectionRef = useFireStore.collection('users').doc(`${currentUser.uid}`);
const storageRef = useStorage.ref("avatars")
const fileRef = storageRef.child(`${uuidv4()}`)
await fileRef.put(file);
const url = await fileRef.getDownloadURL();
await collectionRef.set({
createdAt: timestamp(),
email: currentUser.email,
userid: currentUser.uid,
username: username,
firstname: firstname,
lastname: lastname,
avatar: url
});
history.push("/")
}
Refer: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

I need to use my variable in multiple functions in my component, but can't seem to access it

Here is an example of my code.
let appointment
const [AddMemberTitle] = useMutation(ADD_MEMBER_TITLE_MUTATION)
const [CreateMember] = useMutation(CREATE_MEMBER_MUTATION, {
onCompleted: (newMemberData) => {
setMemberId(newMemberData.CreateMember.id)
//run some code using the Member id and the values from my Formik component and the appointment variable
},
})
const onSubmit = async (values, onSubmitProps) => {
appointment = values.appointment
CreateMember({
variables: {
firstName: values.firstName,
middleName: values.middleName,
lastName: values.lastName,
gender: values.gender,
phoneNumber: values.phoneNumber,
whatsappNumber: values.whatsappNumber,
email: values.email,
dob: values.dob,
maritalStatus: values.maritalStatus,
occupation: values.occupation,
},
})
}
return (
//Then my jsx goes here
)
The rest of the code is working as expected, I just need to run the AddMemberTitle mutation using information that is generated after the CreateMember mutation runs.
I tried creating a variable at the top level of the component, and I'm able to assign a value to it in onSubmit but I'm unable to use it in the onCompleted function of Create Member
One of (a few) solutions can be using a promise returned from the mutation calling function (CreateMember returned from useMutation hook).
You can use await or .then() syntax:
const onSubmit = async (values, onSubmitProps) => {
const {
appointment,
otherFormikValue,
...rest // assuming only CreateMember values and mutation names matching
} = values;
const { data: newMemberData } = await CreateMember({ variables: {...rest} });
const { data: someData } = await InsertAppointmentMember(
{ variables: {
memberId: newMemberData.CreateMember.id,
appointmentId: appointment.id
} });

redux action is not a promise thus cannot use .then method

when my props.postToAllData and props.postToUserData methods are called, it takes a while for the fetch method to make its course. Thus, I am being pushed to another webpage and the new information doesn't show since Im pushing to a new page quicker than my post method. I cant use .then method since this isn't a promise. What can i do to push to after the post method finishes?
const onSubmit = (event) => {
event.preventDefault();
if (ingredientsArray.length !== 0 && instructionsArray.length !== 0) {
props.postToAllData(
{
...recipe,
ingredients: ingredientsArray,
instructions: instructionsArray,
img: isSelectedFile,
author: user.username,
},
),
props.postToUserData(
{
...recipe,
ingredients: ingredientsArray,
instructions: instructionsArray,
img: isSelectedFile,
author: user.username,
},
),
resetForm();
history.push('/dashboard/global');
} else setErrorForm('Please fill in all fields');
};
You can use a middleware for redux called thunk. Thunk allows you to write async actions, which you can't with regular redux.
It'll work like this:
Declare an async action with your api call
const myAsyncAtion = () => {
return async () => {
const response = await apiCall();
return response;
}
}
And just dispatch it in your code like any other action. Now it returns a promise, which you can chain with .then or await. Cheers!
const save = async () => {
await props.myAsyncAction();
console.log('hooray')
// or
props.myAsyncAction().then(() => console.log('hooray'))
}

Setting state after callback with json data

I'm receiving a callback from axios after a post request. The callback contains data that I need to use. I want add the callback json data my existing state - but after googling I learnt that callbacks + usestate hook doesn't work together well.
const [party, setParty] = useState("")
const SubmitParty = (e) => {
e.preventDefault()
const PartyData = {
party: party,
firstname: firstname,
lastname: lastname,
email: email,
number: number
}
axios.post(
'/api/new/party',
{
party: party,
firstname: firstname,
lastname: lastname,
email: email,
number: number
},
{
params: {
"secret_token": logged.token
}
}
).then(res => {
var user = res.data.data;
console.log(user); //I can see the response here and the array I want.
setParty(user);
console.log(party); // returns just a blank line. Expected to be same as user
}).catch(err => {
console.log(err)
alert("Oops something went wrong. If this problem continues, please contact support asap!")
});
}
I tried using a useeffect afterwards, but it's a catch 22, cause I need the state to deal with with in in useeffect accurately.
If you use useEffect like this your component will send the API request and update party when it resolves.
const [party, setParty] = useState("");
useEffect(e => {
e.preventDefault();
const PartyData = {
party: party,
firstname: firstname,
lastname: lastname,
email: email,
number: number
};
axios
.post(
"/api/new/party",
{
party: party,
firstname: firstname,
lastname: lastname,
email: email,
number: number
},
{
params: {
secret_token: logged.token
}
}
)
.then(res => {
var user = res.data.data;
console.log(user); //I can see the response here and the array I want.
setParty(user);
console.log(party); // returns just a blank line. Expected to be same as user
})
.catch(err => {
console.log(err);
alert(
"Oops something went wrong. If this problem continues, please contact support asap!"
);
});
});
By default this will run on every render. If you want the effect to run only once then you should set useEffect's 2nd parameter to be an empty array, or if you only want it to run when a specific few items change then you can put those in the array.

Resources