📱

graphql_flutter でquery/mutateを実行した際に画面がカクつくときはdeepEquals を自前で実装すると直るかも

2025/02/23に公開

GraphQL Flutter https://pub.dev/packages/graphql_flutter を使用していると、query/mutate時に画面がカクつく現象に遭遇しました。
その原因の一端が、Dartの DeepCollectionEquality().equals による再帰的なデータ比較処理にあるようです。

発生していた現象

graphql_flutterのquery/mutation実行時に画面の描画がカクついていました。

原因

正規化されたキャッシュを更新する際に用いられる差分比較の実装にパフォーマンス上の問題が存在しています。
graphql_flutterの差分比較の処理はUIスレッド上で実行されるため、差分比較に時間がかかった結果、Jankが発生していました。

同様の問題がgraphql_flutter リポジトリのIssueにて報告されています。
https://github.com/zino-hofmann/graphql-flutter/issues/1196

解決策

GraphQLClientクラスのdeepEquals引数に関数を渡すことで比較の処理を独自で追加できるため、自前で実装を追加しました。

https://github.com/zino-hofmann/graphql-flutter/blob/74a99bf367e413558902f65bfe2d3c35f1afdfb4/packages/graphql/lib/src/graphql_client.dart#L29

GraphQLClient(
    deepEquals: (Object? a, Object? b) {
        if (identical(a, b)) {
            return true;
        }
        if (a == b) {
            return true;
        }
        if (a is Map) {
            if (b is! Map) {
              return false;
            }
            if (a.length != b.length) return false;
            for (var key in a.keys) {
              if (!b.containsKey(key)) return false;
              if (!_jsonMapEquals(a[key], b[key])) return false;
            }
            return true;
        }
        if (a is List) {
            if (b is! List) {
              return false;
            }
            final length = a.length;
            if (length != b.length) return false;
            for (var i = 0; i < length; i++) {
              if (!_jsonMapEquals(a[i], b[i])) return false;
            }
            return true;
        }
        return false;
    },
)

これにより、パフォーマンスが大幅に改善されました。

まとめ

小さな工夫でパフォーマンスが大幅に改善できるため、同様の問題に直面している場合はぜひ試してみてください。

参考

Discussion