inertia
inertia copied to clipboard
transform method in useForm hook doesn't work
Version:
-
@inertiajs/react
version: 1.0.9
Describe the problem:
I'm re-reporting an issue which was closed in the recent reset of issues, the original is #1131
When using useForm
from the React package, the transform
method doesn't work. The method is defined in the body of the useForm
component, and thus is re-initialized upon re-renders to be the original "placeholder" method.
The transform method needs to be memoized in some way. I submitted #1491 which I've tested and it addresses this issue. It stores the transform
method in a ref
so that when it's value is updated it persists through re-renders.
I fixed this using a ref hook.
const transformRef = useRef({} as any);
useEffect(() => {
transformRef.current = (data: any) => {};
transform(transformRef.current)
});
v1.0.11 - the problem persists. If no changes have been made to the form fields, the transform() method is ignored thus not being called. =(
This problem still persists
Nearly 3 years and this very basic error still persists. It genuinely makes me fear for the longevity of this amazing project. Inertia is the glue that binds the frontend and backend together and is exactly how I want to build projects, I really hope this isn't a foretelling of an eventual death of the project.
For anyone who needs a quick drop-in, I've built out a replacement for useForm
which fixes the transform
bug, and also adds a few other features. Please feel free to use it, improve it, steal it, etc. Hopefully one day it won't be necessary.
@reinink @jessarcher can we get a confirmation you are aware of this bug and that there is a PR open for it? I'm not sure why this bug has been ignored for years now. It's core functionality to one of the best features of this library.
https://github.com/inertiajs/inertia/pull/1718
Surprisingly, it was working fine for me until I made an update and it stopped working, I undid all the changes and it still not working.
I fixed this using a ref hook.
const transformRef = useRef({} as any); useEffect(() => { transformRef.current = (data: any) => {}; transform(transformRef.current) });
Allo! Can anyone reading explain this code snippet for me?
I tried it, and variations thereof, all it did was clear all data on every submit. 😕
I've been looking into this for a few hours and here's a summary of what I think I understand so far:
- That code snippet above can allegedly work around problem.
- This PR looks similar to the code snippet but is deeper: https://github.com/inertiajs/inertia/pull/1718
- This package could also work: https://github.com/aviemet/useInertiaForm
As much as option 3 is great, kudos to the dev!, for me, it would be most interesting to get option 1 working, a temporary patch as we faithfully await option 2 to be merged.
More hints for idea 1 please? Thanks.
Following up on using saeidalidadi's snippet. I got something working.
Before:
transform((data) => {
// REPLACE ME: your transform routine goes here
return data
});
After:
import { useRef, useEffect } from 'react';
// ...
const transformRef = useRef({} as any);
useEffect(() => {
transformRef.current = (data: any) => {
// REPLACE ME: your transform routine goes here
return data
};
transform(transformRef.current)
}, [data]);
Then, add onChange={(e) => setData('REPLACE_ME', e.target.value)}
in as many places as possible to trigger re-renders so that your routine gets reloaded if ever it were to be replaced by the original inertia.js placeholder code.
Surprisingly, it was working fine for me until I made an update and it stopped working, I undid all the changes and it still not working.
Same here. First it is working perfectly fine until I make some modification to the code. But undo changes is not helping either.
One thing I noticed that it is working after the code has an error and fix it. But It is not working after refresh.
@reinink Why isn't this bug fixed? The bug exists already for ages and it's really annoying that the transform
method isn't working properly.
Is there any update on this issue?
I've been looking into this one and believe I arrived at the crux of the confusion. The transform
function is designed to be called in the body of the component, not inside a handler function. As long as you place it in the body, you should be good to go. To give a concrete example:
This works:
const Page = () => {
const { post, transform } = useForm({});
transform((data) => ({ ...data, foo: "bar" }));
const handleSubmit = (e) => {
e.preventDefault();
post("/route");
}
// ...
}
This does not work:
const Page = () => {
const { post, transform } = useForm({});
const handleSubmit = (e) => {
e.preventDefault();
transform((data) => ({ ...data, foo: "bar" }));
// A re-render gets triggered somewhere in `post`,
// which wipes out the `transform` call just made
post("/route");
}
// ...
}
(Discussed here: https://github.com/inertiajs/inertia/pull/1491#issuecomment-2181524223)
Then, as pointed in #1491, I think it should be noted in the docs that transform
is the only method of the useForm
hook that must be called from the component body and not from inside any component's handler function. That would save much time to people trying to use it for the first time...
Thanks @andcl. Could you maybe attempt a PR to the docs?
Done. https://github.com/inertiajs/inertiajs.com/pull/348
Even if the originally intended behavior of the transform method is to be used in the component's body, It will be much more useful if could be used like #1131. At least for me it feels hacky storing a value in a ref or somewhere else to be later used in the transform.
Maybe a solution like the one proposed here could also work.
Another posibility could be to merge the form state with the data provided in the submit method. I would make this have precedence over the current state so it can be overriden. Currently the data is ignored and only the form state is submitted.
form.post(route('my-route'), {
data: {foo: 'bar'} // Merge this with the current form state
})