[Flutter] タブを切り替えるたびに、無駄にリビルドされないようにする


タブを使う時に注意することとしては、

<b>タブを切り替えるたびに、無駄にリビルドされないようにする</b>という点です。


これを回避する方法として、`wantKeepAlive`を使用する方法があります。


wantKeepAliveを使うことによって
- 一つの画面の中で複数の画面を切り替える時にリロードされないようにする
- AutomaticKeepAliveMixinを使うと、Stateが破棄されずに、画面をそのまま保った状態で画面を切り替えられる。

### 事前情報
- inappwebviewを使用


```yaml:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  flutter_inappwebview: ^5.7.2+3
```

### 画面の仕様
- 全ての画面をStatelessで作成した
- ３つのWebViewを作成（Flutter・Swift・Kotlin）

### ソースコード

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            bottom: const TabBar(tabs: <Widget>[
              Tab(icon: Icon(Icons.flutter_dash)),
              Tab(icon: Icon(Icons.apple)),
              Tab(icon: Icon(Icons.android)),
            ]),
          ),
          body: const TabBarView(
            children: <Widget>[
              Page1(),
              Page2(),
              Page3(),
            ],
          ),
        ),
      ),
    );
  }
}

class Page1 extends StatelessWidget {
  const Page1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return InAppWebView(
      initialUrlRequest: URLRequest(
        url: Uri.parse(
          'https://flutter.dev/',
        ),
      ),
    );
  }
}

class Page2 extends StatelessWidget {
  const Page2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return InAppWebView(
      initialUrlRequest: URLRequest(
        url: Uri.parse(
          'https://developer.apple.com/jp/swift/',
        ),
      ),
    );
  }
}

class Page3 extends StatelessWidget {
  const Page3({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return InAppWebView(
      initialUrlRequest: URLRequest(
        url: Uri.parse(
          'https://kotlinlang.org/',
        ),
      ),
    );
  }
}



```

# wantKeepAliveを使用すると。。

### 画面の仕様
- ３つのWebViewでStatefulWidgetを使用
- wantKeepAliveを使用
- ３つのWebViewを作成（Flutter・Swift・Kotlin）



### 使い方

１、StatefulWidgetを使用する。
２、Stateのところに、`AutomaticKeepAliveClientMixin`を追加する。
３、`@override`
   `bool get wantKeepAlive => true;`　を追加する。
4、 Build関数内に`super.build(context);`を追加する。

### 使用例

```dart
class Page1 extends StatefulWidget {
  const Page1({Key? key}) : super(key: key);

  @override
  State<Page1> createState() => _Page1State();
}

class _Page1State extends State<Page1> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
  ・・・省略
  }
}

```


### ソースコード

```dart
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            bottom: const TabBar(tabs: <Widget>[
              Tab(icon: Icon(Icons.flutter_dash)),
              Tab(icon: Icon(Icons.apple)),
              Tab(icon: Icon(Icons.android)),
            ]),
          ),
          body: const TabBarView(
            children: <Widget>[
              Page1(),
              Page2(),
              Page3(),
            ],
          ),
        ),
      ),
    );
  }
}

class Page1 extends StatefulWidget {
  const Page1({Key? key}) : super(key: key);

  @override
  State<Page1> createState() => _Page1State();
}

class _Page1State extends State<Page1> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return InAppWebView(
      initialUrlRequest: URLRequest(
        url: Uri.parse(
          'https://flutter.dev/',
        ),
      ),
    );
  }
}

class Page2 extends StatefulWidget {
  const Page2({Key? key}) : super(key: key);

  @override
  State<Page2> createState() => _Page2State();
}

class _Page2State extends State<Page2> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return InAppWebView(
      initialUrlRequest: URLRequest(
        url: Uri.parse(
          'https://developer.apple.com/jp/swift/',
        ),
      ),
    );
  }
}

class Page3 extends StatefulWidget {
  const Page3({Key? key}) : super(key: key);

  @override
  State<Page3> createState() => _Page3State();
}

class _Page3State extends State<Page3> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return InAppWebView(
      initialUrlRequest: URLRequest(
        url: Uri.parse(
          'https://kotlinlang.org/',
        ),
      ),
    );
  }
}

```


|一つ目のコード |2つ目のコード(wantKeepAliveを使用したコード) |
|---|---|
|![Simulator-Screen-Recording-iPhone-14-Pro-2023-05-28-at-09.20.11.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/1236e370-a07b-df8d-60df-10d326245b06.gif)|![Simulator-Screen-Recording-iPhone-14-Pro-2023-05-28-at-09.18.31.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/3eb3508b-8d55-eef1-c187-4744c89ddf91.gif)|