qwik icon indicating copy to clipboard operation
qwik copied to clipboard

[🐞] routeAction$, action.submit doesn't work when called from useVisibleTask$

Open PacoDu opened this issue 2 years ago • 3 comments

Which component is affected?

Qwik City (routing)

Describe the bug

Calling action.submit from a useVisibleTask$ or useTask$ hangs indefinitely and breaks the application

Reproduction

https://stackblitz.com/edit/qwik-starter-iwkete?file=src/routes/index.tsx

Steps to reproduce

Write "test" in the text field -> useVisibleTask will hang indefinitely

System Info

System:
    OS: macOS 13.3.1
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
    Memory: 6.34 GB / 64.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.0.0 - ~/.nvm/versions/node/v20.0.0/bin/node
    npm: 9.6.4 - ~/.nvm/versions/node/v20.0.0/bin/npm
  Browsers:
    Brave Browser: 111.1.49.120
    Chrome: 112.0.5615.121
    Firefox: 107.0
    Safari: 16.4
  npmPackages:
    @builder.io/qwik: 0.104.0 => 0.104.0 
    @builder.io/qwik-city: ~0.104.0 => 0.104.0 
    undici: 5.22.0 => 5.22.0 
    vite: 4.3.3 => 4.3.3

Additional Information

No response

PacoDu avatar Apr 26 '23 19:04 PacoDu

Actually its doesn't work even in versions 1.0, 1.1 and 1.1.1. I'm copying the exact code I'm testing:

export const useAddLead = routeAction$(async (data, event) => {
    console.log('data:', {...data}, event);
    return {
        success: true,
    }
});
export default component$(() => {
    const action = useAddLead();
    
    return (
        <Form action={action}>
            <div class="grid grid-cols-2 gap-3 bg-white py-2 px-3">
                <div class="flex flex-col">
                    <label for="title" class="text-sm text-slate-500">Title</label>
                    <select id="title" name="title"
                        class="border border-slate-500 rounded-md p-2">
                        <option value="Mr">Mr</option>
                        <option value="Mrs">Mrs</option>
                    </select>
                </div>
                    
                <div class="flex flex-col col-span-2">
                    <label for="message" class="text-sm text-slate-500">Message</label>
                    <textarea id="message" name="message" rows={3} 
                        class="border border-slate-500 rounded-md p-2" />
                </div>
                
                <div class="col-span-2">
                    <button type="submit" role="button"
                        disabled={action.isRunning}
                        class="outline-none bg-indigo-500 hover:bg-indigo-600 px-6 py-2 rounded-md text-sm text-white disabled:bg-slate-400">
                        <span>{action.isRunning ? 'Saving...' : 'Save'}</span>
                    </button>
                    {action.value?.success && <p>Data was submitted.</p>}
                </div>
            </div>
        </Form>
    )
});

When I click on submit button only the button is affected transitioning between "Saving..." to "Save". It is the only behavior that works. The console.log code doesn't show anything.

keuller avatar May 12 '23 16:05 keuller

Hi All, I figured out my issue. The routeAction$ only works if it is inside the layout.tsx or direct into route file. In my case, I was creating it inside my nested child component:

<div class="flex flex-col gap-2 py-2 px-6">
     <h1 class="text-2xl font-semibold">Lead Generator</h1>

    <div class="grid grid-cols-2 gap-2 border border-indigo-600 rounded-md bg-white overflow-hidden">
        <LeadForm />
        
        <LeadList />
    </div>
</div>

The snippet code above was my index.tsxfile, which mean my route file. The routeAction$ was inside the LeadForm.tsx file which is not the route or layout file. When I moved it out the routeAction$ from the child component to the index.tsx file and pass down the action as props to the child component, it works perfectly. The final code is:

export const useAddLead = routeAction$(async (data, event) => {
    await delay(500);
    console.log('data:', {...data});
    return {
        success: true,
    }
});

export default component$(() => {
    const action = useAddLead();
    
    return (
        <div class="flex flex-col gap-2 py-2 px-6">
            <h1 class="text-2xl font-semibold">Lead Generator</h1>

            <div class="grid grid-cols-2 gap-2 border border-indigo-600 rounded-md bg-white overflow-hidden">
                <LeadForm action={action} />
                
                <LeadList />
            </div>
        </div>
    )
});

There is no recommendation in the docs regarding it. I will improve the documentation reinforcing that approach otherwise other developers can do the same mistake I did.

keuller avatar May 13 '23 08:05 keuller

I'm experiencing the same issue. But mine is a global action that's defined in the same file as my page (route).

ffMathy avatar May 15 '23 15:05 ffMathy

I should add that in my case, I have a visible task which calls a react hook, which then calls my action.

ffMathy avatar May 15 '23 20:05 ffMathy

Thsi should be fixed in 1.2.0

manucorporat avatar Jul 05 '23 05:07 manucorporat