diff --git a/src/router.js b/src/router.js index 78aa6d7..663b98c 100644 --- a/src/router.js +++ b/src/router.js @@ -118,24 +118,22 @@ export function Router(props) { const didSuspend = useRef(); didSuspend.current = false; - cur.current = useMemo(() => { + useMemo(() => { // This hack prevents Preact from diffing when we swap `cur` to `prev`: if (this.__v && this.__v.__k) this.__v.__k.reverse(); count.current++; - prev.current = cur.current; - - let p, d, m; - toChildArray(props.children).some(vnode => { - const matches = exec(rest, vnode.props.path, (m = { ...vnode.props, path: rest, query, params, rest: '' })); - if (matches) return (p = cloneElement(vnode, m)); - if (vnode.props.default) d = cloneElement(vnode, m); - }); - - return h(RouteContext.Provider, { value: m }, p || d); }, [url]); + let pr, d, m; + toChildArray(props.children).some(vnode => { + const matches = exec(rest, vnode.props.path, (m = { ...vnode.props, path: rest, query, params, rest: '' })); + if (matches) return (pr = cloneElement(vnode, m)); + if (vnode.props.default) d = cloneElement(vnode, m); + }); + cur.current = h(RouteContext.Provider, { value: m }, pr || d); + // Reset previous children - if rendering succeeds synchronously, we shouldn't render the previous children. const p = prev.current; prev.current = null; diff --git a/test/router.test.js b/test/router.test.js index cd4e069..aad6c66 100644 --- a/test/router.test.js +++ b/test/router.test.js @@ -1,5 +1,6 @@ import { jest, describe, it, beforeEach, expect } from '@jest/globals'; import { h, render } from 'preact'; +import { useState } from 'preact/hooks'; import { html } from 'htm/preact'; import { LocationProvider, Router, useLocation, Route, useRoute } from '../src/router.js'; import lazy, { ErrorBoundary } from '../src/lazy.js'; @@ -55,6 +56,56 @@ describe('Router', () => { }); }); + it('should allow updating props in a route', async () => { + const Home = jest.fn(() => html`

Home

`); + const stack = []; + let loc, set; + + const App = () => { + const [test, setTest] = useState('2'); + set = setTest; + return html` + <${LocationProvider}> + <${Router} + onRouteChange=${url => { + stack.push(url); + }} + > + <${Home} path="/" test=${test} /> + + <${() => { + loc = useLocation(); + }} /> + + `; + } + render( + html`<${App} />`, + scratch + ); + + expect(scratch).toHaveProperty('textContent', 'Home'); + expect(Home).toHaveBeenCalledWith({ path: '/', query: {}, params: {}, rest: '', test: '2' }, expect.anything()); + expect(loc).toMatchObject({ + url: '/', + path: '/', + query: {}, + route: expect.any(Function) + }); + + set('3') + await sleep(1); + + expect(Home).toHaveBeenCalledWith({ path: '/', query: {}, params: {}, rest: '', test: '3' }, expect.anything()); + expect(loc).toMatchObject({ + url: '/', + path: '/', + query: {}, + route: expect.any(Function) + }); + expect(scratch).toHaveProperty('textContent', 'Home'); + }); + it('should switch between synchronous routes', async () => { const Home = jest.fn(() => html`

Home

`); const Profiles = jest.fn(() => html`

Profiles

`);