Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Toggling tabBarHidden destroys the tab's SwiftUI identity, dismissing presented sheets

オープン 初心者向け
#593 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
75/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
react-native, swift, typescript
領域
frontend, mobile

調査の方向性

問題は iOS Swift コードにあります。ios/TabViewImpl.swift の 537-553 行目付近にある hideTabBar 関数を確認してください。修正方法は、条件付きロジックを変更して、iOS 16+ で SwiftUI のアイデンティティを保持するために self.toolbar(flag ? .hidden : .automatic, for: .tabBar) を使用することです。提供された SwiftUI 再現用 Gist を使用して変更をテストし、フラグの切り替えが状態をリセットしたりシートを閉じたりしなくなることを確認してください。この変更は、関数が呼び出されている NewTabView.swiftLegacyTabView.swift の両方に適用する必要があります。

索引モデルが issue の本文から書いたものです。

説明

Before submitting a new issue
  • I tested using the latest version of the library (1.4.0 is both latest and what we ship)
  • I tested using a supported version of react native (0.86.3)
  • I checked for possible duplicate issues
Bug summary

Toggling tabBarHidden at runtime tears down the tab's content and rebuilds it. A sheet presented from inside that tab is dismissed, and any @State in the subtree is lost.

We hit this on the common pattern of hiding the tab bar while the keyboard is up: a user typing in a sheet raises the keyboard, the app sets tabBarHidden, and their sheet disappears mid-edit.

Cause. hideTabBar is a @ViewBuilder whose branch depends on flag:

// ios/TabViewImpl.swift:537-553 @ 1.4.0
@ViewBuilder
func hideTabBar(_ flag: Bool) -> some View {
  #if !os(macOS)
    if flag {
      if #available(iOS 16.0, tvOS 16.0, *) {
        self.toolbar(.hidden, for: .tabBar)
      } else {
        // We fallback to isHidden on UITabBar
        self
      }
    } else {
      self
    }
  #else
    self
  #endif
}

A @ViewBuilder if/else compiles to _ConditionalContent<A, B>. Flipping flag swaps which branch is taken, which changes the view's type, which changes its structural identity. SwiftUI answers an identity change by discarding the subtree and building a new one — taking @State and any anchored presentation with it.

flag is a JS-driven prop, so this happens at runtime rather than once at setup:

ios/TabView/NewTabView.swift:45      .hideTabBar(props.tabBarHidden)
ios/TabView/LegacyTabView.swift:33   .hideTabBar(props.tabBarHidden)
Suggested fix

Take one branch, decided by availability — which is constant at runtime — and let only the toolbar value depend on flag:

@ViewBuilder
func hideTabBar(_ flag: Bool) -> some View {
  #if !os(macOS)
    if #available(iOS 16.0, tvOS 16.0, *) {
      // Keep the tab content's SwiftUI identity when tab-bar visibility changes.
      // Switching between a modified view and `self` tears down presentations
      // anchored in that tab.
      self.toolbar(flag ? .hidden : .automatic, for: .tabBar)
    } else {
      // We fallback to isHidden on UITabBar.
      self
    }
  #else
    self
  #endif
}

.automatic is the documented default for a toolbar's visibility, so the flag == false case keeps its current behaviour while the view keeps its identity. The pre-iOS-16 fallback is unchanged and still cannot hide the bar this way; that branch is now chosen by availability alone, so it no longer participates in identity changes either.

This is the diff we currently carry as a patch:

   @ViewBuilder
   func hideTabBar(_ flag: Bool) -> some View {
     #if !os(macOS)
-      if flag {
-        if #available(iOS 16.0, tvOS 16.0, *) {
-          self.toolbar(.hidden, for: .tabBar)
-        } else {
-          // We fallback to isHidden on UITabBar
-          self
-        }
+      if #available(iOS 16.0, tvOS 16.0, *) {
+        // Keep the tab content's SwiftUI identity when keyboard visibility
+        // changes. Switching between a modified view and `self` tears down
+        // presentations anchored in that tab, including Expo UI sheets.
+        self.toolbar(flag ? .hidden : .automatic, for: .tabBar)
       } else {
+        // We fallback to isHidden on UITabBar.
         self
       }
     #else

Happy to open a PR.

Library version

1.4.0

Environment info
react-native: 0.86.3
expo: 57.0.20
react: 19.2.3
react-native-bottom-tabs: 1.4.0
platform: iOS (real device and simulator)
architecture: Fabric (New Architecture)
Steps to reproduce

The reproduction is pure SwiftUI — no React Native and no dependency on this library, which is what shows the cause is the @ViewBuilder branch rather than anything about the bridge, the props, or the app.

  1. Download IdentityRepro.swift from the gist below
  2. Drop it into an iOS app target, or open it in an Xcode Preview
  3. Increment both counters, and/or tap "present sheet" on either side
  4. Flip the tabBarHidden toggle

Expected: both columns keep their state.
Actual: the UPSTREAM column resets its counter to 0 and dismisses its sheet; the FIXED column keeps both.

The file defines hideTabBar_upstream (verbatim from TabViewImpl.swift) and hideTabBar_fixed (the suggestion above) side by side over identical subtrees.

iOS/tvOS only — .toolbar(_:for: .tabBar) is unavailable on macOS, which is why the library's own function is wrapped in #if !os(macOS).

Reproducible sample code

https://gist.github.com/pawarren/56cbb014c18150e67995bf6f11ff8168

主要言語
TypeScript
スター
1.5k
フォーク
108
平均マージ
12時間 42分
マージ済み PR(30日)
9

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

callstack/react-native-bottom-tabs のほかの issue

callstack/react-native-bottom-tabs の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。