Repository: kyeotic/raviger (ts)

Issue:
Early issue with nested `useRoutes`
Sorry for the vague issue but I just thought I would give you a heads up while investigating. 
Since upgrading to `1.0.0-rc.3` (Also tried `rc6`) we have been having issues with previously working nested `useRoutes`. 

The basic structure of our app is as follow

An "App" with `useRoutes` that either maps to a list page or a view entity page
`basePath` is `foo/bar/entities`
Routes are similar to the following
```
const routes = {
    '/': () => <ListPage />,
    '/:id/*': ({ id }) => (
        <ViewPage id={id} />
    ),
}
```

A view entity page with `useRoutes` that maps to 3 tabs within the page,
`basePath` is `foo/bar/entities/<id>` where `id` is a numeric id. 
Routes are similar to the following
```
const routes = {
    "/tab1": () => <Component1 />,
    "/tab2": () => <Component2 />,
    "/tab3": () => <Component3 />
}
```

Previously (0.5.8) we were using `usePath` within one of the tabs (so 2 `useRoutes` deep) with no problems, it would always return the path we expected (`/tab2`) 
Now however, if you land on tab2 (i.e. start a new browser tab at the  url `foo/bar/entities/1/tab2`) `usePath` will return the correct value (`/tab2`) 
But as soon as you navigate to a different tab `usePath` (called within the tab) starts returning  `/1/<tabNo>`. The `basepath` in the context is correct (has the `id` at the end of the path), but it's like it calculated the `path` based on the `basePath` of the router one level higher. 

```
context = { path: '/1/tab2', basePath: 'foo/bar/entities/1' }
```

I'll keep adding detail to this issue as I investigate, but I thought it might be possible you have an idea what's going on. 

Thanks

Pull request:
always useLocationChange in usePath
fixes #34 

---

`usePath` became needlessly complicated after the `useLocationChange` introduction, relying on both the router context and the location watcher for its path. It only used the inherited `basePath` in one code path, creating inconsistent behavior.

Patch:
diff --git a/src/path.js b/src/path.js
index 48f9bb4..7d32acb 100644
--- a/src/path.js
+++ b/src/path.js
@@ -4,13 +4,9 @@ import { isNode, getSsrPath } from './node.js'
 import { isFunction } from './typeChecks.js'
 
 export function usePath(basePath) {
-  let context = useRouter()
-  let [path, setPath] = useState(context.path || getCurrentPath(basePath))
-  useLocationChange(setPath, {
-    basePath,
-    isActive: !context.path
-  })
-  return context.path || path
+  let [path, setPath] = useState(getCurrentPath(basePath || useBasePath()))
+  useLocationChange(setPath, { basePath })
+  return path
 }
 
 export function useBasePath() {


Test patch:
diff --git a/test/path.spec.js b/test/path.spec.js
index f513ffe..9df959e 100644
--- a/test/path.spec.js
+++ b/test/path.spec.js
@@ -1,6 +1,6 @@
 import React from 'react'
 import { render, act } from '@testing-library/react'
-import { useLocationChange, navigate } from '../src/main.js'
+import { useRoutes, usePath, useLocationChange, navigate } from '../src/main.js'
 
 beforeEach(() => {
   act(() => navigate('/'))
@@ -28,3 +28,57 @@ describe('useLocationChange', () => {
     expect(watcher).not.toBeCalled()
   })
 })
+
+describe('usePath', () => {
+  function Route() {
+    let path = usePath()
+    return <span data-testid="path">{path}</span>
+  }
+  test('returns original path', async () => {
+    act(() => navigate('/'))
+    const { getByTestId } = render(<Route />)
+
+    expect(getByTestId('path')).toHaveTextContent('/')
+  })
+
+  test('returns updated path', async () => {
+    act(() => navigate('/'))
+    const { getByTestId } = render(<Route />)
+    act(() => navigate('/about'))
+
+    expect(getByTestId('path')).toHaveTextContent('/about')
+  })
+
+  test('does not include parent router base path', async () => {
+    function Harness({ routes, basePath }) {
+      const route = useRoutes(routes, { basePath })
+      return route
+    }
+
+    const nestedRoutes = {
+      '/': () => <Route />,
+      '/about': () => <Route />
+    }
+    const routes = {
+      '/': () => <Route />,
+      '/about': () => <Route />,
+      '/nested*': () => <Harness basePath="/nested" routes={nestedRoutes} />
+    }
+
+    const { getByTestId } = render(<Harness routes={routes} />)
+    act(() => navigate('/'))
+    expect(getByTestId('path')).toHaveTextContent('/')
+
+    act(() => navigate('/about'))
+    expect(getByTestId('path')).toHaveTextContent('/about')
+
+    act(() => navigate('/nested/about'))
+    expect(getByTestId('path')).toHaveTextContent('/about')
+
+    // Yes, check twice
+    // This is a regression check for this bug: https://github.com/kyeotic/raviger/issues/34
+    act(() => navigate('/nested/about'))
+    expect(getByTestId('path')).toHaveTextContent('/about')
+    expect(getByTestId('path')).not.toHaveTextContent('/nested')
+  })
+})
diff --git a/test/router.spec.js b/test/router.spec.js
index 24696e0..6da92a3 100644
--- a/test/router.spec.js
+++ b/test/router.spec.js
@@ -129,54 +129,6 @@ describe('useRoutes', () => {
   })
 })
 
-describe('usePath', () => {
-  function Route() {
-    let path = usePath()
-    return <span data-testid="path">{path}</span>
-  }
-  test('returns original path', async () => {
-    act(() => navigate('/'))
-    const { getByTestId } = render(<Route />)
-
-    expect(getByTestId('path')).toHaveTextContent('/')
-  })
-
-  test('returns updated path', async () => {
-    act(() => navigate('/'))
-    const { getByTestId } = render(<Route />)
-    act(() => navigate('/about'))
-
-    expect(getByTestId('path')).toHaveTextContent('/about')
-  })
-
-  test('does not include parent router base path', async () => {
-    function Harness({ routes, basePath }) {
-      const route = useRoutes(routes, { basePath })
-      return route
-    }
-
-    const nestedRoutes = {
-      '/': () => <Route />,
-      '/about': () => <Route />
-    }
-    const routes = {
-      '/': () => <Route />,
-      '/about': () => <Route />,
-      '/nested*': () => <Harness basePath="/nested" routes={nestedRoutes} />
-    }
-
-    const { getByTestId } = render(<Harness routes={routes} />)
-    act(() => navigate('/'))
-    expect(getByTestId('path')).toHaveTextContent('/')
-
-    act(() => navigate('/about'))
-    expect(getByTestId('path')).toHaveTextContent('/about')
-
-    act(() => navigate('/nested/about'))
-    expect(getByTestId('path')).toHaveTextContent('/about')
-  })
-})
-
 describe('useBasePath', () => {
   function Harness({ routes, basePath }) {
     const route = useRoutes(routes, { basePath })