From 2f54bc14699656e6905452a4233d982f83d0001f Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Tue, 16 Mar 2021 09:31:45 -0400 Subject: [PATCH] fix(vue): passing params as props are correctly updated when switching pages (#23049) resolves #23043 --- packages/vue-router/src/viewStacks.ts | 26 ++++- .../vue/test-app/tests/unit/routing.spec.ts | 96 +++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/packages/vue-router/src/viewStacks.ts b/packages/vue-router/src/viewStacks.ts index 45bd6d31a0..f548dcf6eb 100644 --- a/packages/vue-router/src/viewStacks.ts +++ b/packages/vue-router/src/viewStacks.ts @@ -23,7 +23,31 @@ export const createViewStacks = (router: Router) => { } const findViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number, useDeprecatedRouteSetup: boolean = false) => { - return findViewItemByPath(routeInfo.pathname, outletId, false, useDeprecatedRouteSetup); + let viewItem = findViewItemByPath(routeInfo.pathname, outletId, false, useDeprecatedRouteSetup); + + /** + * Given a route such as /path/:id, + * going from /page/1 to /home + * to /page/2 will cause the same + * view item from /page/1 to match + * for /page/2 so we need to make + * sure any params get updated. + * Not normally an issue for accessing + * the params via useRouter from vue-router, + * but when passing params as props not doing + * this would cause the old props to show up. + */ + if (viewItem && viewItem.params !== routeInfo.params) { + /** + * Clear the props function result + * as the value may have changed due + * to different props. + */ + delete viewItem.vueComponentData.propsFunctionResult; + viewItem.params = routeInfo.params; + } + + return viewItem; } const findLeavingViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number, mustBeIonRoute: boolean = true, useDeprecatedRouteSetup: boolean = false) => { diff --git a/packages/vue/test-app/tests/unit/routing.spec.ts b/packages/vue/test-app/tests/unit/routing.spec.ts index 6838f954f0..f44de7189e 100644 --- a/packages/vue/test-app/tests/unit/routing.spec.ts +++ b/packages/vue/test-app/tests/unit/routing.spec.ts @@ -262,4 +262,100 @@ describe('Routing', () => { expect(wrapper.findComponent(Tab1).exists()).toBe(true); expect(wrapper.findComponent(Tab2).exists()).toBe(false); }); + + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/23043 + it('should show the latest props passed to a route', async () => { + const Page1 = { + ...BasePage, + props: { + title: { type: String, default: 'Default Title' } + } + }; + + const Home = { + ...BasePage + } + + const router = createRouter({ + history: createWebHistory(process.env.BASE_URL), + routes: [ + { path: '/', component: Home }, + { path: '/:title', component: Page1, props: true } + ] + }); + + router.push('/'); + await router.isReady(); + const wrapper = mount(App, { + global: { + plugins: [router, IonicVue] + } + }); + + router.push('/abc'); + await waitForRouter(); + + const cmp = wrapper.findComponent(Page1); + expect(cmp.props()).toEqual({ title: 'abc' }); + + router.back(); + await waitForRouter(); + + router.push('/xyz'); + await waitForRouter(); + + const cmpAgain = wrapper.findComponent(Page1); + expect(cmpAgain.props()).toEqual({ title: 'xyz' }); + }); + + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/23043 + it('should call the props function again when params change', async () => { + const Page1 = { + ...BasePage, + props: { + title: { type: String, default: 'Default Title' } + } + }; + + const Home = { + ...BasePage + } + + const propsFn = jest.fn((route) => { + return { title: `${route.params.id} Title` } + }); + + const router = createRouter({ + history: createWebHistory(process.env.BASE_URL), + routes: [ + { path: '/myPath/:id', component: Page1, props: propsFn }, + { path: '/', component: Home } + ] + }); + + router.push('/'); + await router.isReady(); + const wrapper = mount(App, { + global: { + plugins: [router, IonicVue] + } + }); + + router.push('/myPath/123'); + await waitForRouter(); + + const cmp = wrapper.findComponent(Page1); + expect(propsFn.mock.calls.length).toBe(1); + expect(cmp.props()).toEqual({ title: '123 Title' }); + + router.back(); + await waitForRouter(); + + router.push('/myPath/abc'); + await waitForRouter(); + + expect(propsFn.mock.calls.length).toBe(2); + const cmpAgain = wrapper.findComponent(Page1); + expect(cmpAgain.props()).toEqual({ title: 'abc Title' }); + }); });