diff --git a/packages/next/src/build/webpack/loaders/next-flight-loader/action-proxy.ts b/packages/next/src/build/webpack/loaders/next-flight-loader/action-proxy.ts index fe01439e7684..c89eb0f90c47 100644 --- a/packages/next/src/build/webpack/loaders/next-flight-loader/action-proxy.ts +++ b/packages/next/src/build/webpack/loaders/next-flight-loader/action-proxy.ts @@ -4,27 +4,34 @@ export default function createActionProxy( action: any, originalAction?: any ) { - action.$$typeof = Symbol.for('react.server.reference') - action.$$id = id - action.$$bound = bound + function bindImpl(this: any, _: any, ...boundArgs: any[]) { + const currentAction = this - action.bind = function (_: any, ...boundArgs: any[]) { const newAction = async function (...args: any[]) { if (originalAction) { return originalAction(newAction.$$bound.concat(args)) } else { // In this case we're calling the user-defined action directly. - return action(...newAction.$$bound, ...args) + return currentAction(...newAction.$$bound, ...args) } } for (const key of ['$$typeof', '$$id', '$$FORM_ACTION']) { // @ts-ignore - newAction[key] = action[key] + newAction[key] = currentAction[key] } + // Rebind args - newAction.$$bound = (action.$$bound || []).concat(boundArgs) + newAction.$$bound = (currentAction.$$bound || []).concat(boundArgs) + + // Assign bind method + newAction.bind = bindImpl.bind(newAction) return newAction } + + action.$$typeof = Symbol.for('react.server.reference') + action.$$id = id + action.$$bound = bound + action.bind = bindImpl.bind(action) } diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index 5b818691a388..bac683067307 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -123,6 +123,16 @@ createNextDescribe( }, '/header?result=122') }) + it('should support chained .bind', async () => { + const browser = await next.browser('/server') + + await browser.elementByCss('#add3').click() + + await check(() => { + return browser.eval('window.location.pathname + window.location.search') + }, '/header?result=6') + }) + it('should support notFound (javascript disabled)', async () => { const browser = await next.browser('/server', { // TODO we should also test this with javascript on but not-found is not implemented yet. diff --git a/test/e2e/app-dir/actions/app/server/form.js b/test/e2e/app-dir/actions/app/server/form.js index 41158c34e98f..2793a18dd1f7 100644 --- a/test/e2e/app-dir/actions/app/server/form.js +++ b/test/e2e/app-dir/actions/app/server/form.js @@ -34,6 +34,11 @@ export default function Form() { redirect('/header?result=' + (a + b + Number(formData.get('n')))) } + async function add3(a, b, c) { + 'use server' + redirect('/header?result=' + (a + b + c)) + } + return ( <>
@@ -66,6 +71,16 @@ export default function Form() { -1 +
+
+ +
) }