Reputation: 162
I’ve been experimenting around with this for quite a while but I haven’t been able to quite figure this out. I am trying to get a synchronous Meteor method call going in a React class component, as part of a registration form I’m doing up. Basically I continually check if a username is taken every time the username input field changes (onChange) and update a visual indicator. I know this isn't ideal design as once you scale it out, it's costly database calls, so I will change this/throttle it as needed, but that's after I get this basic functionality down.
Here is my Meteor method on the server:
checkUsername({ username }) {
var result = false;
if (username != "") {
if (Accounts.findUserByUsername(username)) {
result = true;
}
}
return result;
},
Here is my function in a React class component:
async checkUsername(username) {
Session.set("usernameValid", true);
var syncCall = await Meteor.call(
"checkUsername",
{
username,
}
);
// Shouldn't the line of code below run only AFTER the call above completes?
if (syncCall === false) Session.set("usernameValid", false);
return Session.get("usernameValid");
}
I understand that this shouldn't need to be async, nor should I need await. Furthermore I know this code is wrong since syncCall will always be undefined. This is where I check for username availability:
if (username === "") {
this.state.username = false;
this.setFeedback("username", "", false);
}
else if (this.checkUsername(username)) {
// Username is valid and available
console.log("Username is available!");
this.state.username = username;
this.setFeedback("username", "", true);
}
else {
// Username is invalid and nonempty
console.log("Username is invalid/unavailable!");
this.state.username = false;
this.setFeedback("username", "Username is invalid/unavailable :-(", false);
}
The issue is that the checkUsername function returns before the Meteor call completes, and hence the state isn't updated in time and I can't check that either.
How do I go about forcing this to be synchronous? I read about Meteor.wrapAsync()
but I couldn't nail how to incorporate it properly (or even if it's the right way to go about it). Any help is appreciated, thank you!
Upvotes: 3
Views: 139
Reputation: 21354
Meteor method calls on the client do not return a Promise, so you can't await
them. You need to provide a callback function:
checkUsername(username) {
Session.set("usernameValid", true);
Meteor.call("checkUsername", {username},
(isTaken) => isTaken && Session.set("usernameValid", false));
}
However with React I wouldn't use session variables. React has it's own support for reactive state variables via useState
and it's much better integrated:
const [usernameValid, setUsernameValid] = useState(false);
...
checkUsername(username) {
Meteor.call("checkUsername", {username}, setUsernameValid);
}
Upvotes: 1