Everytime I'm on my purchase page everything works and updates fine. When I hit submit for the first time in the page it updates my db correctly but alert window does not pop up. => Page rerenders and sets itself to initial view. If I stay on the page and submit a second purchase then I get a pop up box that says failure to fetch in post method and then the alert box saying that the purchase was successful pops up. Even though the failure occurred nothing is functionally wrong. All database documents are up to date. Somebody please help I have no clue what I'm doing wrong.
my front end react.js
import React, { useState, useEffect } from 'react';
import { NumberFormat as numberFormat } from '../numberFormat';
export default function Purchase() {
// user input collection structure
const [form, setForm] = useState({
amount: '',
title: '',
})
// user spending limit
const [limit, setLimit] = useState({
balance: 0,
limit: 0,
})
useEffect(() => {
async function getLimit() {
const response = await fetch(`http://localhost:4000/balance/`);
if (!response.ok) {
const message = `An error occured at effect: ${response.statusText}`;
window.alert(message);
return;
}
const data = await response.json();
const userBal = data["balance"];
const userLim = 50 - parseFloat(userBal);
setLimit({ balance: userBal, limit: userLim });
}
getLimit();
return;
}, []);
// Update State Properties
function updateForm(value) {
return setForm((prev) => {
return { ...prev, ...value };
});
}
function validateInput(input){
input = input * 1000;
if (input === 0) return false;
else return true;
}
async function onSubmit() {
// check that amount is valid
if (form.title === ''){
window.alert(`Please Include a Title for the payment`);
return;
}
const bal = parseFloat(limit.balance);
const lim = parseFloat(limit.limit);
const amt = parseFloat(form.amount);
if (amt > lim || amt === 0 || amt === '' || validateInput(amt)){
window.alert(`Invalid Amount ${form.amount}.\nPlease enter value greater than 0.00 within ${lim}.`);
return;
}
const newPurchase = {
type: 'purchase',
amount: form.amount,
title: form.title,
balanceToSet: amt bal
}
await fetch(`http://localhost:4000/purchase/add`, {
method: 'POST',
mode:'cors',
headers: {
'Access-Control-Allow-Origin': '*',
"Content-Type": 'application/json; charset=UTF-8',
},
body: JSON.stringify(newPurchase)
}
)
.then((response) => response.json()).then((data)=> {console.log(data);
})
.catch((err) => {
window.alert(`post fetch error ${err.message}`);
return;
});
window.alert(`Purchase ${form.title} of amount $${form.amount} posted.`);
return;
}
return (
// Will Display
<div className='home'>
{/* Title */}
<h1 className='hometitle'>
Make A Purchase
</h1>
<div>
<h1> Your Fizz Balance: {numberFormat(limit.balance)}</h1>
<h1> Your Fizz Allowance: {numberFormat(limit.limit)}</h1>
</div>
{/* Current Allowance */}
{/* Debt owed to fizz */}
{/* Make Purchase Form
If incorrect parameters then show text saying invalid amount below
On submission alert shows telling user a purchase of certain amount was made
render rest of the page */}
<form onSubmit={onSubmit}>
<div className="form-group">
<label htmlFor='title'>Title:</label>
<input
type='text'
id='name'
value={form.title}
onChange={(e) => updateForm({ title: e.target.value })}
/>
</div>
<div className="form-group">
<label htmlFor="amount">Amount:</label>
<input
type="text"
id="amount"
value={form.amount}
onChange={(e) => updateForm({ amount: e.target.value })}
/>
</div>
<div>
<input
type='submit'
value='Make Purchase'
/>
</div>
</form>
</div>
);
}
my backend node.js
const express = require("express");
const purchaseRoutes = express.Router();
const dbo = require("../db/connection");
const { floor } = require('mathjs');
// Add purchase to History Table and update balance in user info
purchaseRoutes.route("/purchase/add").post(
async function (req, response) {
let db_connect = dbo.getDb();
// Writing Purchase to History Table
let thisPurchase = {
type: req.body.type,
amount: parseFloat(req.body.amount),
title: req.body.title,
rfndStatus: false,
date: Date.now()
};
let queryParams = { name: "user" };
// post query contents
let updatedBalance = {
$set: {
balance: floor(req.body.balanceToSet * 1000) / 1000
}
};
const session = db_connect.startSession();
const transactionDetails = {
readPreference: 'primary',
readConcern: { level: 'local' },
writeConcern: { w: 'majority' }
}
try {
const transactionResults = await session.withTransaction(async () => {
const userColl = db_connect.db('fizzData').collection('userData');
const histColl = db_connect.db('fizzData').collection('transHist');
await userColl.updateOne(queryParams, updatedBalance,{session});
await histColl.insertOne(thisPurchase,{session});
}, transactionDetails);
response.json(transactionResults);
console.log(transactionResults);
} catch(e){
console.log(`transaction failed ${e}`)
}
finally {
await session.endSession();
}
});
in postman I tested my fetch call using the same header, url, and body and my response was this.
{"ok":1,"$clusterTime":{"clusterTime":{"$timestamp":"7171344646893731861"},"signature":{"hash":"qwfNCLTeYc /Gr79JghaSuDtZvQ=","keyId":{"low":8,"high":1659459863,"unsigned":false}}},"operationTime":{"$timestamp":"7171344646893731861"}}
I thought it could have been a cors issue so I installed the cors extension in chrome and added the mode tag to the header. The problem is not with the fetch in useEffect or at least the call because it correctly calls the right values from the database.
CodePudding user response:
Seems like user agent is not aware that the form event is getting handled.
To resolve this, modify your onSubmit
function as follows:
async function onSubmit(event) {
event?.preventDefault();
// ... rest of
// ... of the
// ... code
}
See if it works :)
EDIT: more info on above topic.
import "./styles.css";
export default function App() {
const onSubmit = (formEvent) => {
// if you comment this line
// you will see that console.log("Line got executed"); will print and the window will get reloaded and console.log is gone
formEvent.preventDefault();
// The above line with prevent reloading of the window
console.log("Line got executed");
};
const onButtonClick = (buttonEvent) => {
// if we comment this out the button will SUMBIT the form
buttonEvent.preventDefault();
// The above line with prevent submission of the form
// because this button is of type submit and it's default action is to submit the form
// so by adding above line we are disabling its default behavior
console.log("Button is clicked not for submission");
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input id="form-input" />
<button type="submit" onClick={onButtonClick}>
Submit or click
</button>
</form>
</div>
);
}
Codesandbox link to play around: https://codesandbox.io/s/react-preventdefault-udx49m?file=/src/App.js:0-1053