Repository: kyeotic/raviger
Pull request #53 (2020-04-30 15:54:21)

Macku fix hooks deps
Extends #52


Patch:
diff --git a/.gitignore b/.gitignore
index 5f8c14b..e566ff5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,7 @@ example/dist/*
 /themes/
 
 # misc
+.idea
 .DS_Store
 .env.local
 .env.development.local
@@ -38,4 +39,4 @@ yarn-debug.log*
 yarn-error.log*
 .vscode/
 coverage/
-/junit.xml
\ No newline at end of file
+/junit.xml
diff --git a/Makefile b/Makefile
index 1f6d0da..e44c121 100644
--- a/Makefile
+++ b/Makefile
@@ -23,3 +23,5 @@ run-docs: ## Run in development mode
 docs: ## Build the site
 	cd docs && hugo -t learn -d public --gc --minify --cleanDestinationDir
 
+sync-docs: ## update docs theme submodules
+	git submodule update --init --recursive
\ No newline at end of file
diff --git a/src/router.js b/src/router.js
index 883c0d4..85aa1df 100644
--- a/src/router.js
+++ b/src/router.js
@@ -45,10 +45,9 @@ function matchRoute(
   if (matchTrailingSlash && path && path[path.length - 1] === '/') {
     path = path.substring(0, path.length - 1)
   }
-  const routePaths = Object.keys(routes)
   const routeMatchers = useMemo(
-    () => routePaths.map(createRouteMatcher),
-    routePaths
+    () => Object.keys(routes).map(createRouteMatcher),
+    [hashRoutes(routes)]
   )
   // Hacky method for find + map
   let routeMatch
@@ -88,3 +87,12 @@ function createRouteMatcher(routePath) {
   route.push(propList ? propList.map(paramName => paramName.substr(1)) : [])
   return route
 }
+
+// React doesn't like when the hook dependency array changes size
+// >> Warning: The final argument passed to useMemo changed size between renders. The order and size of this array must remain constant.
+// It is recommended to use a hashing function to produce a single, stable value
+// https://github.com/facebook/react/issues/14324#issuecomment-441489421
+function hashRoutes(routes) {
+  const paths = Object.keys(routes).sort()
+  return paths.join(':')
+}


Test patch:
diff --git a/test/router.spec.js b/test/router.spec.js
index 6da92a3..916ad1b 100644
--- a/test/router.spec.js
+++ b/test/router.spec.js
@@ -127,6 +127,40 @@ describe('useRoutes', () => {
     act(() => navigate('/users/1'))
     expect(getByTestId('label')).toHaveTextContent('User 1')
   })
+
+  test('handles dynamic routes', async () => {
+    const Harness = () => {
+      const [myRoutes, setRoutes] = React.useState(routes)
+
+      const addNewRoute = () => {
+        setRoutes(prevRoutes => {
+          return {
+            ...prevRoutes,
+            '/new': () => <Route label="new route" />
+          }
+        })
+      }
+
+      const route = useRoutes(myRoutes) || <span data-testid="label">not found</span>
+
+      return (
+        <>
+          {route}
+          <button onClick={addNewRoute} data-testid="add-route">Add route</button>
+        </>
+      )
+    }
+
+    const { getByTestId } = render(<Harness/>)
+    act(() => navigate('/new'));
+    expect(getByTestId('label')).not.toHaveTextContent('new route')
+
+    const button = getByTestId('add-route')
+
+    act(() => button.click())
+    act(() => navigate('/new'));
+    expect(getByTestId('label')).toHaveTextContent('new route')
+  })
 })
 
 describe('useBasePath', () => {