在 Ionic/React 中使用 `history.push` 并将 `IonTabs` 作为嵌套路由后,页面未呈现

我有一个带有 IonReactRouter 的 Ionic/React v5.0.7 应用程序来管理路由:

// App.tsx

return (
  <IonApp>
    <IonReactRouter history={history}>
      <IonRouterOutlet>
        <Route exact path={ROUTES.HOME} component={Home} />
        <Route exact path={ROUTES.LOGIN} component={Login} />
        <Route path={ROUTES.CONTRACTOR} component={ContractorDashboard} />
      </IonRouterOutlet>
    </IonReactRouter>
  </IonApp>
)

在我的一条路线( path={ROUTES.CONTRACTOR} )中,我正在尝试实现 IonTabs ,它需要有自己的 IonRouterOutlet ,所以我将选项卡作为嵌套路由,如下所示:

// ContractorDashboard.tsx

<IonContent>
  <IonTabs>
    <IonTabBar slot="top">
      <IonTabButton href="/contractor/overview" tab="contractor-overview">
        <IonLabel>{t('ContractorDashboard.contractorOverview')}</IonLabel>
      </IonTabButton>
      <IonTabButton href="/contractor/contractor-configs" tab="contractor-configs">
        <IonLabel>{t('ContractorDashboard.contractorConfig')}</IonLabel>
      </IonTabButton>
      <IonTabButton href="/contractor/workers-management" tab="workers-management">
        <IonLabel>{t('ContractorDashboard.workersManagement')}</IonLabel>
      </IonTabButton>
      <IonTabButton href="/contractor/email-responses" tab="email-responses">
        <IonLabel>Some label</IonLabel>
      </IonTabButton>
    </IonTabBar>

    <IonRouterOutlet>
      <Route path="/contractor/contractor-configs" render={() => <ContractorConfigs userId={authUser.uid} />} />
      <Route path="/contractor/workers-management" component={WorkersManagement} />
      <Route path="/contractor/email-responses" render={() => <EmailResponses userId={authUser.uid} />} />
      <Route path="/contractor/contractor-overview" render={() => <IonTitle>Title</IonTitle>} />
      <Route exact path="/contractor" render={() => <Redirect to="/contractor/overview" />} />
    </IonRouterOutlet>

  </IonTabs>
</IonContent>

一切正常,直到我尝试使用 /contractorhistory.push('/contractor') 创建到 <Redirect to="/contractor" /> 路由的动态导航,这是选项卡路由器的根。

在我的登录组件中,如果用户通过身份验证,我想自动重定向到 ContractorDashboard 。 IE。成功登录后,用户应该被重定向到仪表板。我实现了以下内容:

// Login.tsx

useEffect(() => {
  if (authUser) {
    history.push('/contractor')
  }
}, [authUser, history])

发生的情况是地址栏中的 URL 已更改,但登录页面仍然可见,而不是 ContractorDashboard 。我也试过这个:

// Login.tsx

if (authUser) {
  return <Redirect to="/contractor"/>
}

return (
// ...
)

结果是一样的。我可以在开发工具中看到承包商页面,但它没有呈现。
不过有几点注意事项:

  • 当我尝试不同的事情时,结果会有所不同,比如推送到 /contractor/overview 只插入 /contractor 。然后承包商仪表板可见一秒钟,然后又是登录页面。
  • 有时我确实得到了仪表板,但选项卡不可见。它在 DOM 中,并且光标事件在那里但仍然不可见。
  • 在仪表板中使用 IonTabs 之前一切正常。
  • 奇怪的是,当我尝试使用经过身份验证的用户通过地址栏导航到登录页面时,我被重定向到仪表板,一切正常。

我确实尝试用 IonReactRouter 中的 Router 替换 react-router ,就像 this answer 中建议的那样。然后从登录页面重定向有效,但选项卡会在每次选项卡更改时触发整个页面刷新,这只是糟糕的用户体验。

这是我的 ionic info 输出:

Ionic:

   Ionic CLI : 6.11.0

Utility:

   cordova-res : not installed
   native-run  : not installed

System:

   NodeJS : v12.18.3
   npm    : 6.14.6
   OS     : Windows 10

这是我的 package.json

{
  "name": "application",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "@capacitor/android": "^2.4.6",
    "@capacitor/core": "2.4.6",
    "@ionic/react": "^5.0.7",
    "@ionic/react-router": "^5.0.7",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.4.0",
    "@testing-library/user-event": "^8.0.3",
    "@types/jest": "^24.0.25",
    "@types/node": "^12.12.24",
    "@types/react": "^16.9.17",
    "@types/react-dom": "^16.9.4",
    "@types/react-router": "^5.1.4",
    "@types/react-router-dom": "^5.1.3",
    "firebase": "^8.2.3",
    "i18next": "^19.8.4",
    "i18next-http-backend": "^1.0.22",
    "ionicons": "^5.0.0",
    "react": "^16.13.0",
    "react-dom": "^16.13.0",
    "react-i18next": "^11.8.5",
    "react-redux": "^7.2.2",
    "react-router": "^5.1.2",
    "react-router-dom": "^5.1.2",
    "react-scripts": "^4.0.1",
    "redux": "^4.0.5",
    "redux-localstorage-simple": "^2.3.1",
    "redux-thunk": "^2.3.0",
    "typescript": "3.8.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "appium": "appium --chromedriver-executable C:UsersOricodechromedriverschromedriver-83-0-4103.exe",
    "e2e:android": "protractor e2e/android-e2e.conf.js",
    "e2e:web": "protractor e2e/web-e2e.conf.js"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@capacitor/cli": "2.4.6",
    "@types/jasmine": "^3.6.3",
    "@types/jasminewd2": "^2.0.8",
    "@types/react-redux": "^7.1.15",
    "@types/redux-logger": "^3.0.8",
    "appium": "^1.20.2",
    "jasmine": "^3.6.4",
    "jasmine-spec-reporter": "^6.0.0",
    "protractor": "^7.0.0",
    "redux-logger": "^3.0.6",
    "ts-node": "^9.1.1"
  },
  "description": "An Ionic project"
}

那么有没有办法正确实现这一点以及如何实现呢?
如果此处缺少任何信息或代码,请告诉我。
任何帮助将不胜感激!

更新
因此,对于任何有兴趣的人,我都放弃了寻找解决方案。相反,我实现了我自己的基本选项卡,没有路由(从来不明白为什么选项卡需要路由......)。
忽略样式很简单:


const [tab, setTab] = useState<number>(0);
const mapTabs = [
  'contractorOverview',
  'contractorConfigs',
  'workersManagement',
  'emailResponses'
]

const handleTabChange = () => {
  switch (tab) {
    case 0: return <h3>Overview</h3>;
    case 1: return authUser && <ContractorConfigs userId={authUser.uid} />;
    case 2: return <WorkersManagement />;
    case 3: return authUser && <EmailResponses userId={authUser.uid} />;
    default: return <h3>Overview</h3>;
  }
}

return (
  // ....
  <IonContent>
    <IonToolbar color="secondary">
      <IonButtons slot="start">
        {mapTabs.map((_tab, tabIdx) => (
          <IonButton
            key={tabIdx}
            id={`${_tab}`}
            onClick={() => setTab(tabIdx)}
            disabled={mapTabs[tab] === _tab}
          >
            {t(`ContractorDashboard.${_tab}`)}
          </IonButton>
        ))}
      </IonButtons>
    </IonToolbar>

    {handleTabChange()}

  </IonContent>
  // ....
)

这就是拥有工作标签视图所需的全部内容(同样,如果没有一些样式,它看起来不会那么好)。
如果有人对标签问题有解决方案(实际上我不是 100% 确定导致问题的原因......我无法在 stackblitz 中重现......)我很想听听。
如果没有,我会将其发布为答案...

stack overflow Page is not rendering after using `history.push` in Ionic/React with `IonTabs` as nested routes
原文答案

答案:

作者头像

你有没有尝试过:

history.push({ pathname: '/contractor' })

或者

history.push({ pathname: '/contractor/overview' }); 
作者头像

你试过了吗...

history.push('/contractor/overview')

你能在 stackblitz 或 codesandbox 上发布一个小项目吗?

作者头像

在我正在导航的页面的根部有一个组件来解决我的问题。参见 https://github.com/ionic-team/ionic-framework/issues/19622