URL 更改但页面新页面未呈现 Ionic React ,具有历史记录的 IonReactRouter
URL changes but page new page is not rendered Ionic React , IonReactRouter with history
我正在使用 Ionic 5 与 React 和 Redux 编写一个应用程序。我尝试在成功登录后导航到新页面 /tabs/home。当我从后端获得成功响应时,我试图通过将新的 URL 推送到 react router history 道具上来做到这一点。这是有效的,因为它将 url 从 /login 更改为 /tabs/home 但仍显示登录页面。
index.tsx
import React from 'react';
import {render} from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './helpers/store';
import { Router } from 'react-router';
import CreateBrowserHistory from 'history/createBrowserHistory';
export const history = CreateBrowserHistory();
render(
<Provider store={store}>
<Router history={history}>
<App />
</Router>
</Provider>,
document.getElementById('root')
);
App.tsx
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { history } from './index';
import { alertActions } from './actions/alert.actions';
import { Route } from 'react-router-dom';
import {
IonApp,
} from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import { LoginPage } from './pages/Login';
import MainTabs from './pages/MainTabs';
function App() {
const alert = useSelector(state => state.alert);
const dispatch = useDispatch();
useEffect(() => {
history.listen((location, action) => {
console.log(location);
console.log(action);
dispatch(alertActions.clear());
});
}, []);
return (
<IonApp>
{/*
// @ts-ignore*/}
<IonReactRouter history={history}>
<Route path="/tabs" component={MainTabs} />
<Route path="/login" component={LoginPage} />
</IonReactRouter>
</IonApp>
)
}
export default App;
Login.tsx
function LoginPage() {
const [inputs, setInputs] = useState({
username: '',
password: ''
});
const [submitted, setSubmitted] = useState(false);
const { username, password } = inputs;
const loggingIn = useSelector(state => state.authentication.loggingIn);
const dispatch = useDispatch();
useEffect(() => {
dispatch(userActions.logout());
}, []);
function handleChange(e) {
const { name, value } = e.target;
setInputs(inputs => ({ ...inputs, [name]: value }));
}
function handleSubmit(e) {
e.preventDefault();
setSubmitted(true);
if (username && password) {
dispatch(userActions.login(username, password));
}
}
return (
<IonPage id="login-page">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton></IonMenuButton>
</IonButtons>
<IonTitle>Login</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<form noValidate onSubmit={handleSubmit}>
<IonList>
<IonItem>
<IonLabel position="stacked" color="primary">Username</IonLabel>
<IonInput name="username" type="text" value={username} spellCheck={false} autocapitalize="off" onIonChange={handleChange} className={'form-control' + (submitted && !username ? ' is-invalid' : '')} required>
</IonInput>
</IonItem>
<IonItem>
<IonLabel position="stacked" color="primary">Password</IonLabel>
<IonInput name="password" type="password" value={password} onIonChange={handleChange} className={'form-control' + (submitted && !password ? ' is-invalid' : '')} required>
</IonInput>
</IonItem>
</IonList>
<IonRow>
<IonCol>
{loggingIn && <span className="spinner-border spinner-border-sm mr-1"></span>}
<IonButton type="submit" expand="block">Login</IonButton>
</IonCol>
<IonCol>
<IonButton routerLink="/signup" color="light" expand="block">Signup</IonButton>
</IonCol>
</IonRow>
</form>
</IonContent>
</IonPage>
)
}
export { LoginPage };
登录操作
function login(username, password) {
return dispatch => {
dispatch(request({ username }));
userService.login(username, password)
.then(
user => {
dispatch(success(user));
history.push('/tabs/home');
},
error => {
dispatch(failure(error.toString()));
dispatch(alertActions.error(error.toString()));
}
);
};
function request(user) { return { type: userConstants.LOGIN_REQUEST, user } }
function success(user) { return { type: userConstants.LOGIN_SUCCESS, user } }
function failure(error) { return { type: userConstants.LOGIN_FAILURE, error } }
}
只需在Route中加入exact
属性即可解决
<Route path="/tabs" exact component={MainTabs} />
<Route path="/login" exact component={LoginPage} />
在你的代码中你有
<Route path "/tabs" component={MainTabs} />
什么时候应该
<Route path "/tabs/home" component={MainTabs} />
当您尝试使用 /tabs/home
推送您的历史记录时,没有为此指定路线,因此它不知道去哪里。
同样在你的索引文件中,我建议有一个像这样的额外路由
<Route exact path "/tabs" component={SomeComponent} />
<Route path "/tabs/home" component={MainTabs} />
以防万一您计划将多条路径附加到您的 /tabs
路线。
问题:
根据文档:
IonReactRouter
组件包装了来自 React Router 的传统 BrowserRouter
组件,并为应用程序设置路由。因此,使用 IonReactRouter
代替 BrowserRouter
。您可以将任何道具传递给 IonReactRouter
,它们将传递给基础 BrowserRouter
.
我认为 BrowserRouter
不支持自定义 history
,如您所见 BrowserRouter
支持此道具,那里没有 history
道具
basename
forceRefresh
getUserConfirmation
keyLength
children
history
道具可用于 Router
解决方案:
所以我为使用自定义历史记录做了以下更改并且它正在工作
index.js
import React from "react";
import { render } from "react-dom";
import App from "./App";
import { Provider } from "react-redux";
import { store } from "./helpers/store";
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
App.tsx
<IonApp>
<Router history={history}>
{/* <IonReactRouter history={history}> */}
<Route path="/tabs" component={MainTabs} />
<Route exact path="/" component={LoginPage} />
{/* </IonReactRouter> */}
</Router>
</IonApp>
或
你可以用这样的东西作为 hack,ref
import React from 'react'
import { History } from 'history'
import { useHistory } from 'react-router'
// Add custom property 'appHistory' to the global window object
declare global {
interface Window { appHistory: History }
}
const MyApp: React.FC = () => {
// Store the history object globally so we can access it outside of React components
window.appHistory = useHistory()
...
}
我正在使用 Ionic 5 与 React 和 Redux 编写一个应用程序。我尝试在成功登录后导航到新页面 /tabs/home。当我从后端获得成功响应时,我试图通过将新的 URL 推送到 react router history 道具上来做到这一点。这是有效的,因为它将 url 从 /login 更改为 /tabs/home 但仍显示登录页面。
index.tsx
import React from 'react';
import {render} from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './helpers/store';
import { Router } from 'react-router';
import CreateBrowserHistory from 'history/createBrowserHistory';
export const history = CreateBrowserHistory();
render(
<Provider store={store}>
<Router history={history}>
<App />
</Router>
</Provider>,
document.getElementById('root')
);
App.tsx
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { history } from './index';
import { alertActions } from './actions/alert.actions';
import { Route } from 'react-router-dom';
import {
IonApp,
} from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import { LoginPage } from './pages/Login';
import MainTabs from './pages/MainTabs';
function App() {
const alert = useSelector(state => state.alert);
const dispatch = useDispatch();
useEffect(() => {
history.listen((location, action) => {
console.log(location);
console.log(action);
dispatch(alertActions.clear());
});
}, []);
return (
<IonApp>
{/*
// @ts-ignore*/}
<IonReactRouter history={history}>
<Route path="/tabs" component={MainTabs} />
<Route path="/login" component={LoginPage} />
</IonReactRouter>
</IonApp>
)
}
export default App;
Login.tsx
function LoginPage() {
const [inputs, setInputs] = useState({
username: '',
password: ''
});
const [submitted, setSubmitted] = useState(false);
const { username, password } = inputs;
const loggingIn = useSelector(state => state.authentication.loggingIn);
const dispatch = useDispatch();
useEffect(() => {
dispatch(userActions.logout());
}, []);
function handleChange(e) {
const { name, value } = e.target;
setInputs(inputs => ({ ...inputs, [name]: value }));
}
function handleSubmit(e) {
e.preventDefault();
setSubmitted(true);
if (username && password) {
dispatch(userActions.login(username, password));
}
}
return (
<IonPage id="login-page">
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton></IonMenuButton>
</IonButtons>
<IonTitle>Login</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<form noValidate onSubmit={handleSubmit}>
<IonList>
<IonItem>
<IonLabel position="stacked" color="primary">Username</IonLabel>
<IonInput name="username" type="text" value={username} spellCheck={false} autocapitalize="off" onIonChange={handleChange} className={'form-control' + (submitted && !username ? ' is-invalid' : '')} required>
</IonInput>
</IonItem>
<IonItem>
<IonLabel position="stacked" color="primary">Password</IonLabel>
<IonInput name="password" type="password" value={password} onIonChange={handleChange} className={'form-control' + (submitted && !password ? ' is-invalid' : '')} required>
</IonInput>
</IonItem>
</IonList>
<IonRow>
<IonCol>
{loggingIn && <span className="spinner-border spinner-border-sm mr-1"></span>}
<IonButton type="submit" expand="block">Login</IonButton>
</IonCol>
<IonCol>
<IonButton routerLink="/signup" color="light" expand="block">Signup</IonButton>
</IonCol>
</IonRow>
</form>
</IonContent>
</IonPage>
)
}
export { LoginPage };
登录操作
function login(username, password) {
return dispatch => {
dispatch(request({ username }));
userService.login(username, password)
.then(
user => {
dispatch(success(user));
history.push('/tabs/home');
},
error => {
dispatch(failure(error.toString()));
dispatch(alertActions.error(error.toString()));
}
);
};
function request(user) { return { type: userConstants.LOGIN_REQUEST, user } }
function success(user) { return { type: userConstants.LOGIN_SUCCESS, user } }
function failure(error) { return { type: userConstants.LOGIN_FAILURE, error } }
}
只需在Route中加入exact
属性即可解决
<Route path="/tabs" exact component={MainTabs} />
<Route path="/login" exact component={LoginPage} />
在你的代码中你有
<Route path "/tabs" component={MainTabs} />
什么时候应该
<Route path "/tabs/home" component={MainTabs} />
当您尝试使用 /tabs/home
推送您的历史记录时,没有为此指定路线,因此它不知道去哪里。
同样在你的索引文件中,我建议有一个像这样的额外路由
<Route exact path "/tabs" component={SomeComponent} />
<Route path "/tabs/home" component={MainTabs} />
以防万一您计划将多条路径附加到您的 /tabs
路线。
问题:
根据文档:
IonReactRouter
组件包装了来自 React Router 的传统 BrowserRouter
组件,并为应用程序设置路由。因此,使用 IonReactRouter
代替 BrowserRouter
。您可以将任何道具传递给 IonReactRouter
,它们将传递给基础 BrowserRouter
.
我认为 BrowserRouter
不支持自定义 history
,如您所见 BrowserRouter
支持此道具,那里没有 history
道具
basename
forceRefresh
getUserConfirmation
keyLength
children
history
道具可用于 Router
解决方案:
所以我为使用自定义历史记录做了以下更改并且它正在工作
index.js
import React from "react";
import { render } from "react-dom";
import App from "./App";
import { Provider } from "react-redux";
import { store } from "./helpers/store";
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
App.tsx
<IonApp>
<Router history={history}>
{/* <IonReactRouter history={history}> */}
<Route path="/tabs" component={MainTabs} />
<Route exact path="/" component={LoginPage} />
{/* </IonReactRouter> */}
</Router>
</IonApp>
或
你可以用这样的东西作为 hack,ref
import React from 'react'
import { History } from 'history'
import { useHistory } from 'react-router'
// Add custom property 'appHistory' to the global window object
declare global {
interface Window { appHistory: History }
}
const MyApp: React.FC = () => {
// Store the history object globally so we can access it outside of React components
window.appHistory = useHistory()
...
}