Reputation: 6049
I am creating a page in which the user needs to enter the details to add the product to the product list. If the user accidentally moves out of that page after inputting some data in the form, confirmation should be mandatory from the user before moving out. But I am struggling with this requirement. I am using the react-hook-form
for storing the data in the JSON server.
I am using a state leave
, if it true then alert the user before moving out else nothing.
const [leave, setLeave] = useState(false);
Now, I don't know where and how to use this state for displaying the alert box before leaving. Here my form which will render.
render (
<Form onSubmit={handleSubmit(onSubmit)}>
<Form.Row>
<Form.Group as={Col} className="mr-5">
<Form.Label column>Product Name</Form.Label>
<Form.Control
name="productName"
placeholder="Enter product Name"
required
ref={register}
/>
</Form.Group>
</Form.Row>
<Button variant="success" type="submit" className="text-white mt-5">
Add New Product
</Button>
</Form>
<Prompt when={Leave} message="Are you sure you want to leave ?" /> {/*Here I have promted*/}
);
For simplicity, I have given only one input field. Now function definition of onSubmit is given below.
const onSubmit = (formData) => {
setLeave(true); //here I am setting this true
axios.post("http://localhost:4000/products", formData);
navigation.push({
pathname: "/productList",
state: { added: "pass" },
});
};
This will work when I submitting the form but I want to prompt when the user clicks on the back button or any navigation link.
Upvotes: 2
Views: 11343
Reputation: 1443
In functional component of reactjs I used below thing. this worked for me. In my case when leaving current page I want to remove some store data. In that case i used below thing.
useEffect(() => {
return () => {
// you can add your functionality here
};
}, []);
Upvotes: 2
Reputation: 6049
I have updated the state isDirty
or leave
to true when there is a change in the input field of the form as shown below
render (
<Form onSubmit={handleSubmit(onSubmit)}>
<Form.Row>
<Form.Group as={Col} className="mr-5">
<Form.Label column>Product Name</Form.Label>
<Form.Control
name="productName"
placeholder="Enter product Name"
required
onChange={() => setIsDirty(true)} {/* I have updated here*/}
ref={register}
/>
</Form.Group>
</Form.Row>
<Button variant="success" type="submit" className="text-white mt-5">
Add New Product
</Button>
</Form>
<Prompt when={isDirty} message="Are you sure you want to leave ?" />
);
Now inside the onSubmit function, I have updated the isDirty
state to false before navigating to the destination.
const onSubmit = (formData) => {
axios.post("http://localhost:4000/products", formData);
setIsDirty(false); //here I am setting this true
navigation.push({
pathname: "/productList",
state: { added: "pass" },
});
};
I'd like to share an important point here that whenever there is a change in input at any point then only
isDirty
state istrue
and during submission of the form (all input fields are filled) the state change tofalse
so that it can navigate to another URL.
Upvotes: 2
Reputation: 1011
when
must be true when you want to interrupt navigation.
I would rename your variable to something like isDirty
, initialised as false
. I've found since I started naming my boolean flags like this my mind has to do a little less work to understand what it might be being used for.
Flip it to true
when the first change is made to the form values. Could be simply a useEffect
with formData
as a dependency? Check its not already flipped to prevent unnecessary renders.
Flip it back to false when you get a 200 from your submission to allow the subsequent navigation.
I don't think React will re-render before the Prompt gets fired in your current onSubmit
, so you may need to figure out a way to navigate after verifying the submission.
Another flag like didSubmit
would allow you a code path to render a <Redirect>
instead of calling navigation.push()
, if that suits.
But otherwise, using your current setup, can can allow navigation when you land on a fresh form (your user hasn't committed any effort yet), navigation will be interrupted if the form is 'dirty', and navigation will happen automatically on the next render after setting didSubmit
.
const [isDirty, setIsDirty] = React.useState(false)
const [didSubmit, setDidSubmit] = React.useState(false)
const onSubmit = async (formData) => {
try {
await axios.post('url', formData)
setIsDirty(false)
setDidSubmit(true)
} catch (error) {
// handle your errors
}
}
React.useEffect(() => {
if(!isDirty) setIsDirty(true)
}, [formData])
React.useEffect(() => {
if(didSubmit) navigation.push({ ... })
}, [didSubmit]
return (
// the form...
<Prompt when={isDirty} {...} />
)
Upvotes: 1