I'm using React 16.13 and Bootstrap 4. I have the following form container ...
const FormContainer = (props) => {
...
const handleFormSubmit = (e) => {
e.preventDefault();
CoopService.save(coop, setErrors, function(data) {
const result = data;
history.push({
pathname: "/" + result.id + "/people",
state: { coop: result, message: "Success" },
});
window.scrollTo(0, 0);
});
};
return (
<div>
<form className="container-fluid" onSubmit={handleFormSubmit}>
<FormGroup controlId="formBasicText">
...
{/* Web site of the cooperative */}
<Button
action={handleFormSubmit}
type={"primary"}
title={"Submit"}
style={buttonStyle}
/>{" "}
{/*Submit */}
</FormGroup>
</form>
</div>
);
Is there a standard way to disable the submit button to prevent a duplicate form submission? The catch is if there are errors in the form that come back from the server, I would like the button to be enabled again. Below is the "CoopService.save" I referenced above ...
...
save(coop, setErrors, callback) {
// Make a copy of the object in order to remove unneeded properties
coop.addresses[0].raw = coop.addresses[0].formatted;
const NC = JSON.parse(JSON.stringify(coop));
delete NC.addresses[0].country;
const body = JSON.stringify(NC);
const url = coop.id
? REACT_APP_PROXY + "/coops/" + coop.id + "/"
: REACT_APP_PROXY + "/coops/";
const method = coop.id ? "PUT" : "POST";
fetch(url, {
method: method,
body: body,
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.ok) {
return response.json();
} else {
throw response;
}
})
.then((data) => {
callback(data);
})
.catch((err) => {
console.log("errors ...");
err.text().then((errorMessage) => {
console.log(JSON.parse(errorMessage));
setErrors(JSON.parse(errorMessage));
});
});
}
Not sure if it's relevant, but here is my Button component. Willing to change it or the above to help with implementing a standard, out-of-the-box way to solve this.
import React from "react";
const Button = (props) => {
return (
<button
style={props.style}
className={
props.type === "primary" ? "btn btn-primary" : "btn btn-secondary"
}
onClick={props.action}
>
{props.title}
</button>
);
};
export default Button;
Greg already mentioned this link to show you how you can use component state to store whether or not the button is disabled.
However the latest version of React uses functional components with hooks rather than this.state
or this.setState(...)
. Here's how you might go about that:
import { useState } from 'react';
const FormContainer = (props) => {
...
const [buttonDisabled, setButtonDisabled] = useState(false);
...
const handleFormSubmit = (e) => {
setButtonDisabled(true); // <-- disable the button here
e.preventDefault();
CoopService.save(coop, (errors) => {setButtonDisabled(false); setErrors(errors);}, function(data) {
const result = data;
history.push({
pathname: "/" + result.id + "/people",
state: { coop: result, message: "Success" },
});
window.scrollTo(0, 0);
});
};
return (
...
<Button
action={handleFormSubmit}
disabled={buttonDisabled} // <-- pass in the boolean
type={"primary"}
title={"Submit"}
style={buttonStyle}
/>
...
);
const Button = (props) => {
return (
<button
disabled={props.disabled} // <-- make sure to add it to your Button component
style={props.style}
className={
props.type === "primary" ? "btn btn-primary" : "btn btn-secondary"
}
onClick={props.action}
>
{props.title}
</button>
);
};
I wrote some messy inline code to replace your setErrors
function, but chances are you probably want to add setButtonDisabled(false);
to the setErrors
function wherever you originally defined it, rather than calling it from an anonymous function like I did; so keep that in mind.
More info about the useState
hook can be found here. Let me know if that answers your question.