【问题标题】:URL changes but page new page is not rendered Ionic React , IonReactRouter with historyURL 更改但页面新页面未呈现 Ionic React ,具有历史记录的 IonReactRouter
【发布时间】:2020-10-06 19:16:28
【问题描述】:

我正在使用带有 React 和 Redux 的 Ionic 5 编写应用程序。在成功登录尝试后,我正在尝试导航到新页面 /tabs/home。当我从后端获得成功响应时,我试图通过将新 URL 推送到反应路由器历史记录道具上来做到这一点。这是因为它将 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;

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

【问题讨论】:

    标签: reactjs ionic-framework react-redux react-router ionic-react


    【解决方案1】:

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

     <Route path="/tabs" exact component={MainTabs} />
     <Route path="/login" exact component={LoginPage} />
    

    【讨论】:

    • 不幸的是,这对我不起作用,但感谢您的建议。它仍在更新 URL,但未呈现新页面。
    【解决方案2】:

    在你的代码中你有

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

    【讨论】:

    • /tabs/home 的路由在 MainTabs 组件中,并且有从 /tabs 到 /tabs/home 的重定向。我可能错了,但我认为即使是无法找到路线的问题,它仍然应该尝试呈现新页面,而不仅仅是停留在当前页面上
    【解决方案3】:

    问题:

    根据文档:

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

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

    basename
    forceRefresh
    getUserConfirmation
    keyLength
    children
    

    history 道具可用于Router

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

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

    【讨论】:

    • 感谢您的建议。我添加了 IonRouterOutlet 标记,但据我所知,它没有改变任何东西。
    • 是否可以在零食博览会上创建一个示例演示?
    • @Stalfurion,发现问题并更新了答案,请看一下
    • @Stalfurion,很高兴知道,它有帮助:)
    猜你喜欢
    • 2021-05-02
    • 1970-01-01
    • 1970-01-01
    • 2019-03-09
    • 2020-01-31
    • 1970-01-01
    • 2020-08-12
    • 2019-08-06
    • 1970-01-01
    相关资源
    最近更新 更多