SolidJS Router useNavigate() throws: Error: Make sure your app is wrapped in a <Router />

SolidJS Router useNavigate() throws: Error: Make sure your app is wrapped in a <Router />

即使我的应用程序包含在 Router 标记中,当我使用 useNavigate()<Navigate /> 元素时,我也会遇到相同的错误 login.tsx:27 Error: Make sure your app is wrapped in a <Router />

这是我的 index.tsx

/* @refresh reload */
import { render } from 'solid-js/web';

import './index.css';
import App from './App';
import { Router } from 'solid-app-router';

render(
    () => (
        <Router>
            <App />
        </Router>
    ),
    document.getElementById('root') as HTMLElement
)

App.tsx

const App: Component = () => {
    return (
        <>
            <Routes>
                <Route path="/" component={Landing} />
                <Route path="/dashboard" component={Dashboard} />
            </Routes>
        </>
    )
}

作为登录组件父级的登陆组件

import { useNavigate } from 'solid-app-router'
import { Component, createSignal, Show, onMount } from 'solid-js'
import { getIsValidSession } from '../services/session'
import '../styling/landing.css'
import CreateAccount from './landing/create-account'
import Login from './landing/login'

const Landing: Component = () => {
    const [displayLogin, setDisplayLogin] = createSignal(true)

    return (
        <div class="landing text-center">
            <main class="form-signin">
                <img
                    class="mb-4"
                    src="src/assets/original/tracker-image.png"
                    alt=""
                    width="72"
                    height="85"
                />
                <Show when={displayLogin()} fallback={<CreateAccount />}>
                    <Login />
                </Show>

                <Show
                    when={displayLogin()}
                    fallback={
                        <button
                            class="w-100 btn btn-lg btn-primary mt-3"
                            onClick={toggleDisplay}>
                            Login Existing User
                        </button>
                    }>
                    <button
                        class="w-100 btn btn-lg btn-primary mt-3"
                        onClick={toggleDisplay}>
                        Create Account
                    </button>
                </Show>
            </main>
        </div>
    )
}

export default Landing

和登录组件

import { useNavigate } from 'solid-app-router'
import { Component, createSignal } from 'solid-js'
import Response from '../../models/response'
import { PostSession, Session } from '../../models/session'
import * as session from '../../services/session'

const Login: Component = () => {
    const [email, setEmail] = createSignal('')
    const [password, setPassword] = createSignal('')

    const login = async (event: any) => {
        event.preventDefault()
        try {
            console.log(`Login: ${email()}, Password: ${password()}`)
            const res = await session.login({
                email: email(),
                password: password(),
            } as PostSession)

            if (res.status !== 200) {
                window.alert('Login failed')
            } else {
                const navigate = useNavigate()
                navigate('/dashboard', { replace: true })
            }
        } catch (error) {
            console.error(error)
        }
    }

    return (
        <form>
            <h1 class="h3 mb-3 fw-normal">Please sign in</h1>

            <div class="form-floating">
                <input
                    type="email"
                    class="form-control"
                    id="floatingInput"
                    placeholder="name@example.com"
                    value={email()}
                    onChange={(e: any) => setEmail(e.target.value)}
                />
                <label for="floatingInput">Email address</label>
            </div>
            <div class="form-floating">
                <input
                    type="password"
                    class="form-control"
                    id="floatingPassword"
                    placeholder="Password"
                    value={password()}
                    onChange={(e: any) => setPassword(e.target.value)}
                />
                <label for="floatingPassword">Password</label>
            </div>

            <div class="checkbox mb-3">
                <label>
                    <input type="checkbox" value="remember-me" /> Remember me
                </label>
            </div>
            <button
                class="w-100 btn btn-lg btn-primary"
                onClick={e => login(e)}>
                Sign in
            </button>
        </form>
    )
}

export default Login

为我的用例设置路由器的正确方法是什么?

这里的问题(我认为)是您在事件处理程序中使用 useNavigate()。该函数需要在渲染期间“在树内”同步调用,而不是在不具有相同执行上下文的回调中调用。试试这个:

    const [email, setEmail] = createSignal('')
    const [password, setPassword] = createSignal('')
    const navigate = useNavigate()

然后像以前一样在您的事件处理程序中使用它:

        } else {
            navigate('/dashboard', { replace: true })
        }

这样行吗?