Несмотря на то, что мое приложение заключено в тег 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>
</>
)
}
посадочный компонент, который является родителем компонента Login
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.info(`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 = "[email protected]"
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 })
}
Это работает?
Да, это так! Хороший улов!