4

我正在使用带有 React 和 Redux 的 Ionic 5 编写应用程序。在成功登录尝试后,我正在尝试导航到新页面 /tabs/home。当我从后端获得成功响应时,我试图通过将新 URL 推送到反应路由器历史记录道具上来做到这一点。这是因为它将 url 从 /login 更改为 /tabs/home 但仍然显示登录页面。

索引.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')
);

应用程序.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;

登录.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 } }
}
4

3 回答 3

3

只需将exact属性放在 Route 中即可解决此问题

 <Route path="/tabs" exact component={MainTabs} />
 <Route path="/login" exact component={LoginPage} />
于 2020-06-17T23:22:17.070 回答
1

在您的代码中,您有

<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路线。

于 2020-06-19T12:56:49.847 回答
1

问题 :

根据文档:

IonReactRouter组件包装了BrowserRouter来自 React Router 的传统组件,并将应用程序设置为路由。因此,请使用IonReactRouter. BrowserRouter您可以将任何道具传递给IonReactRouter,它们将被传递给底层BrowserRouter

我认为自定义history不受支持BrowserRouter,正如您所见BrowserRouter,支持此道具,那里没有history道具

basename
forceRefresh
getUserConfirmation
keyLength
children

history道具可用于Router

github上的问题


解决方案 :

所以我对使用自定义历史进行了以下更改并且它正在工作


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")
);

应用程序.tsx

    <IonApp>
      <Router history={history}>
        {/* <IonReactRouter history={history}> */}
        <Route path="/tabs" component={MainTabs} />
        <Route exact path="/" component={LoginPage} />
        {/* </IonReactRouter> */}
      </Router>
    </IonApp>

或者

你可以使用这样的东西作为hack,参考

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()

  ...
}
于 2020-06-19T14:32:37.460 回答