Multiple actions with different unique names seem to trigger each other's submission.result effects

Did I miss something obvious in the reproduction (stackblitz link)? It seams like the two components would be pretty isolated.
1. Open up the browser's console (stackblitz's console is not enough). 2. Let everything load and click the "Go 1" button once 3. Look at the browser's log. https://stackblitz.com/edit/github-28x64bqv-omzmyg2i?file=src%2Froutes%2Findex.tsx GOT
Why does clicking on "Go 1" trigger createEffect on submission result 2 (below: `myAction result 2 undefined`)?

myAction result 1 undefined
myAction result 2 undefined
myAction 1
myAction result 1 undefined
myAction result 2 undefined
Why does clicking on "Go 1" trigger createEffect on submission result 2 (below: `myAction result 2 undefined`)?

myAction result 1 undefined
myAction result 2 undefined
myAction 1
myAction result 1 undefined
myAction result 2 undefined
EXPECTED
Clicking on "Go 1" should only trigger createEffect on submission result 1. Is solid-router trying to clear the "result" before running the action even though I did not call "submission.clear()"?

myAction result 1 undefined
myAction 1
myAction result 1 undefined
Clicking on "Go 1" should only trigger createEffect on submission result 1. Is solid-router trying to clear the "result" before running the action even though I did not call "submission.clear()"?

myAction result 1 undefined
myAction 1
myAction result 1 undefined
EXPECTED (better yet, now I can easily run logic once on non-error status results even if the server function returns no result aka undefined)
Clicking on "Go 1" should only trigger createEffect on submission result 1 AFTER the run (not before).

myAction 1
myAction result 1 undefined
Clicking on "Go 1" should only trigger createEffect on submission result 1 AFTER the run (not before).

myAction 1
myAction result 1 undefined
5 Replies
peerreynders
peerreynders7d ago
function Submit(props: {
action: Action<[id: number], void, [id: number]>;
id: number;
}) {
const callAction = useAction(props.action);
const submission = useSubmission(props.action);
createEffect<number | undefined>((lastArg) => {
// Obtain submission argument
// OR subscribe to submission argument for next pass
const arg = submission.input?.[0];

if (!lastArg) {
if (arg !== props.id) return undefined;

// subscribe to result/error
const _result = submission.result;
const _error = submission.error;
return arg;
}

// result or error
const [result, error] = untrack(() => {
const resultTuple = [submission.result, submission.error];
submission.clear();
return resultTuple;
});

console.log('myAction error/result', props.id, error, result);

return undefined;
}, undefined);

return <button on:click={() => callAction(props.id)}>Go {props.id}</button>;
}
function Submit(props: {
action: Action<[id: number], void, [id: number]>;
id: number;
}) {
const callAction = useAction(props.action);
const submission = useSubmission(props.action);
createEffect<number | undefined>((lastArg) => {
// Obtain submission argument
// OR subscribe to submission argument for next pass
const arg = submission.input?.[0];

if (!lastArg) {
if (arg !== props.id) return undefined;

// subscribe to result/error
const _result = submission.result;
const _error = submission.error;
return arg;
}

// result or error
const [result, error] = untrack(() => {
const resultTuple = [submission.result, submission.error];
submission.clear();
return resultTuple;
});

console.log('myAction error/result', props.id, error, result);

return undefined;
}, undefined);

return <button on:click={() => callAction(props.id)}>Go {props.id}</button>;
}
peerreynders
peerreynders7d ago
You really can't understand this stuff until you start messing with useSubmissions (plural). https://stackblitz.com/edit/solidjs-templates-7u2yad?file=src%2Fapp.tsx
useSubmissions - SolidDocs
Documentation for SolidJS, the signals-powered UI framework
peerreynders
StackBlitz
solid.js action cache interplay - StackBlitz
A Solid TypeScript project based on @solidjs/router, solid-js, typescript, vite and vite-plugin-solid
slim (jamesc)
slim (jamesc)OP7d ago
That explains the extra calls in createEffect. I see your createEffect is accessing input, pending, and result and putting those into console.table. It makes sense that you would see all the events in that case, input changes before the submit so that explains it. It still seems off in my case though, my createEffect accesses only result but I still see the same number of calls that your seeing even when result had not changed yet. In any event, I'm using this to capture a non-error result (return a value or not):
createEffect(on(()=> submission.pending, (pending, prevPending) =>{
if(prevPending === true && !submission.error) {
console.log('success');
}
}, {defer: true}))
createEffect(on(()=> submission.pending, (pending, prevPending) =>{
if(prevPending === true && !submission.error) {
console.log('success');
}
}, {defer: true}))
And the thing that matters the most: Why does clicking on "Go 1" trigger createEffect on submission result 2
peerreynders
peerreynders7d ago
The router has exactly one submissions queue. Submissions are matched by their url to the base of the action function. Given that both myAction1 and myAction2 use exactly the same action function goAction, their base URL is identical. The myAction1 and myAction2 names only come into play during hydration for forms. Other than that the actions are identical (in terms of the client/server relation they do exactly the same thing). So what is happening here is that submissions tracks goAction invocations, not myAction1 or myAction2 submissions. That is why in my example I used the submission arguments to discriminate between “action 1” and “action 2” submissions. Only when the effect saw that the outbound submission arguments were tied to the component's instance did it even subscribe to the next inbound result from that particularsubmission instance (and given that there may not be a result but an error that had to be subscribed for as well; finally the submission was cleared so it wouldn't hang around and be accidentally referenced later again). If I had to track multiple concurrent submissions I'd probably make the first submission argument a correlation identifier to cut down on potential confusion.
Enterprise Integration Patterns
Correlation Identifier - Enterprise Integration Patterns
How does a requestor that has received a reply know which request this is the reply for?
action - SolidDocs
Documentation for SolidJS, the signals-powered UI framework
GitHub
solid-router/src/data/action.ts at c05ce351b584a8db2247ddb7863915fd...
A universal router for Solid inspired by Ember and React Router - solidjs/solid-router
slim (jamesc)
slim (jamesc)OP6d ago
Thanks! Guess I was getting confused with query, the " higher-order function" that considers the arguments.

Did you find this page helpful?