I am having a really bizarre bug. Occasionally, when I submit the form the "userId" cookie is not updated. I think I have isolated the problem to something to do with
return user.set({
roomId: roomId,
name: name
}).then(() => alert("finished writing"))
as when the cookie isn't updated the "finished writing" alert is never called. I think it is something to with a promise not being resolved, and that taking up the thread so the .then is never run (and consequently the .then with the cookie update is never run). However, I don't really understand promises and I can't find what might be holding it up. If anyone could help me out or point out the bug it would be really appreciated. Here is the code:
function GamePage() {
const {roomId} = useParams();
const db = firebase.firestore();
let history = useHistory();
const [userIdExistsButWrongRoom, setUserIdExistsButWrongRoom] = useState(true);
const userId = cookies.get('userId');
useEffect(() => {
if(!(typeof(userId)==="undefined")){
db.collection("users").doc(userId).get().then(function(doc){
if(doc.data().roomId === roomId){
setUserIdExistsButWrongRoom(false);
}
});
}
}, [db,roomId,userId]);
if(cookies.get('roomId')===roomId){
if(typeof(userId)==="undefined"){
return (
<div>
<EnterName />
</div>
);
} else {
if(userIdExistsButWrongRoom){
return (
<div>
<EnterName />
</div>
);
} else {
return (
<div>
<Game />
</div>);
}
}
} else {
history.push("/");
return (<div />);
}
}
function EnterName() {
const {roomId} = useParams();
const [name, setName] = useState("");
function handleChange(event) {
setName(event.target.value);
}
function handleSubmit(event) {
addNewUser(roomId,name).then(function(userId) {cookies.set('userId',userId)});
}
return (<form onSubmit={handleSubmit}>
<label>
Name:
<textarea value={name} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>);
}
function Game() {
const {roomId} = useParams();
return (<div>
<h1>
{roomId}
</h1>
</div>);
}
//Add a new user with server generated unique ID, and the given room ID to the database
//Returns the doc
function addNewUser(roomId,name) {
const db = firebase.firestore();
const user = db.collection("users").doc()
const userId = user.id;
alert(userId);
return user.set({
roomId: roomId,
name: name
}).then(() => alert("finished writing"));
}
Edit
After Oliver's answer, I tried implementing an asynchoronus submitHandler. However, this caused the addNewUser function to not even be called. I found this question javascript async await Submitting a form with onsubmit using Promise which suggests that the problem with an asynchronus submitHandler is that it always returns a promise so it submits before the Promise resolves. I tried implementing their proposed fix (below) but now it is back to the orginal problem but just all the time now!
function EnterName() {
const {roomId} = useParams();
const [name, setName] = useState("");
function handleChange(event) {
setName(event.target.value);
}
async function handleSubmit(event) {
let userId = await addNewUser(roomId, name);
alert("test");
cookies.set('userId',userId);
}
function submit(event){
handleSubmit(event);
return false;
}
return (<form onSubmit={submit}>
<label>
Name:
<textarea value={name} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>);
}
function Game() {
const {roomId} = useParams();
return (<div>
<h1>
{roomId}
</h1>
</div>);
}
//Add a new user with server generated unique ID, and the given room ID to the database
//Returns the doc
async function addNewUser(roomId,name) {
const db = firebase.firestore();
const user = db.collection("users").doc()
const userId = user.id;
alert(userId);
return user.set({
roomId: roomId,
name: name
}).then(() => {
alert("finished writing");
return userId;
});
}