Search code examples
routessolid-jssolid-start

Error: <A> and 'use' router primitives can be only used inside a Route


A new commer to solid.js, I'm following a tutorial to get some A routing in solid.js app's navbar . My App.jsx is code is like this:

import { Router, Route, A } from "@solidjs/router";
import Home from './pages/Home';
import About from './pages/About';
import Test from './routes/Test';
import Cart from './pages/Cart';
  
function App() {
  const [darkTheme, setDarkTheme] = createSignal(false)

  function toggleTheme() {
    setDarkTheme(!darkTheme())
  }

  return (
    <div class="container m-auto bg">
      <header
        class="my-4 p-2 text-xl flex items-center gap-4 justify-end"
        classList={{"bg-neutral-900": darkTheme(), "text-white": darkTheme() }}
      >
        <span 
          class="material-symbols-outlined cursor-pointer"
          onClick={toggleTheme}
        >light_mode</span>
        <h1 class="mr-auto">Ninja Merch</h1>

        <A href="/">Home</A>
        <A href="/cart">Cart</A>
      </header>
      
      <img class="rounded-md" src={banner} alt="site banner" />

        <Router>
          <Route path="/" component={Home} />
          <Route path="/cart" component={Cart} />
      </Router>
      
    </div>
  );
}

export default App;

However I get a blank screen with this console error:

    utils.js?v=92765ccd:29 Uncaught 
Error: <A> and 'use' router primitives can be only used inside a Route.
    at invariant (utils.js?v=92765ccd:29:15)
    at useRouter (routing.js?v=92765ccd:9:32)
    at useRoute (routing.js?v=92765ccd:11:75)
    at useResolvedPath (routing.js?v=92765ccd:13:19)
    at A (components.jsx:15:14)
    at chunk-JG2I5HKG.js?v=92765ccd:633:14
    at untrack (chunk-JG2I5HKG.js?v=92765ccd:513:12)
    at Object.fn (chunk-JG2I5HKG.js?v=92765ccd:629:11)
    at runComputation (chunk-JG2I5HKG.js?v=92765ccd:809:22)
    at updateComputation (chunk-JG2I5HKG.js?v=92765ccd:788:3)

I tried several different arrangements of A tag to no avail. The docs did not help either, as it does not have a similar example.

So appreciate your hints to fix this.


Solution

  • You can use an A element under a Route component as navigation items are always associated with a route.

    const Home = () => (
      <div>
        <ul>
          <li><A href='/blog'>Blog</A></li>
          <li><A href='/users'>Users</A></li>
        </ul>
        <div>This is home page!</div>
      </div>
    );
    

    So, your app should look like this:

    import { A, Route, Router } from '@solidjs/router';
    import { render } from 'solid-js/web';
    
    function App() {  
      const Home = () => (
        <div>
          <ul>
            <li><A href='/blog'>Blog</A></li>
            <li><A href='/users'>Users</A></li>
          </ul>
          <div>This is home page!</div>
        </div>
      );
    
      const Users = () => <div>Users</div>;
      const Blog = () => <div>Blog</div>;
      const NotFound = () => <div>NotFound</div>;
    
      return (
        <Router>
          <Route path="/" component={Home} />
          <Route path="/users" component={Users} />
          <Route path="/blog" component={Blog} />
          <Route path="*404" component={NotFound} />
        </Router>
      );
    }
    
    render(() => <App />, document.body);
    

    If you want to pass A directly as you did in your demo, you can create a wrapper component so that A is always under a Router component:

    const Layout: Component<{ children: JSX.Element }> = (props) => {
      return (
        <div>
          {props.children}
        </div>
      );
    };
    
    const Home: Component<{}> = () => (
      <Layout>
        <ul>
          <li><A href='/'>Home</A></li>
          <li><A href='/blog'>Blog</A></li>
          <li><A href='/users'>Users</A></li>
        </ul>
      </Layout>
    );
    

    Alternatively, you can move the layout items including header under the layout component:

    const Layout: Component<{ children: JSX.Element }> = (props) => {
      return (
        <div>
          <ul>
            <li><A href='/'>Home</A></li>
            <li><A href='/blog'>Blog</A></li>
            <li><A href='/users'>Users</A></li>
          </ul>
          {props.children}
        </div>
      );
    };
    

    Now, the App component becomes:

    import { A, Route, Router } from '@solidjs/router';
    import { Component, JSX } from 'solid-js';
    import { render } from 'solid-js/web';
    
    const Layout: Component<{ children: JSX.Element }> = (props) => {
      return (
        <div>
          <ul>
            <li><A href='/'>Home</A></li>
            <li><A href='/blog'>Blog</A></li>
            <li><A href='/users'>Users</A></li>
          </ul>
          {props.children}
        </div>
      );
    };
    
    const Home: Component<{}> = () => <Layout><div>This is Home page!</div></Layout>
    const Users: Component<{}> = () => <Layout><div>This is Users page!</div></Layout>
    const Blog: Component<{}> = () => <Layout><div>This is Blog page!</div></Layout>
    const NotFound: Component<{}> = () => <Layout><div>Not Found!</div></Layout>
    
    function App() {
      return (
        <Router>
          <Route path="/" component={Home} />
          <Route path="/users" component={Users} />
          <Route path="/blog" component={Blog} />
          <Route path="*404" component={NotFound} />
        </Router>
      );
    }
    
    render(() => <App />, document.body);
    

    See this answer for details: SolidJS Uncaught Error: <A> and 'use' router primitives can be only used inside a Route