Upgrade to Pro — share decks privately, control downloads, hide ads and more …

About Flutter Architecture

About Flutter Architecture

About Flutter Architecture

Daichi Furiya (Wasabeef)

February 18, 2024
Tweet

More Decks by Daichi Furiya (Wasabeef)

Other Decks in Programming

Transcript

  1. About me Daichi Furiya (߱໼ େ஍) Google Developers Expert CyberAgent,

    Inc. @wasabeef_jp wasabeef    • ࢁསࢢग़਎ (ؠԼԹઘͷۙ͘)
  2. Flutter 2023 ೥ͷ Flutter/Dart Ξοϓσʔτ 1 ݄ 5 ݄ 8

    ݄ 11 ݄ Flutter 3.7 Flutter 3.13 Flutter 3.10 Flutter 3.16 Dart 2.19 3.0 alpha Dart 3 Dart 3.2 Dart 3.1 Dart
  3. Apps made with Flutter 500k+ apps created 2m+ developers 48k+

    Flutter & Dart packages 1k+ Every day, new apps
  4. TanStack Query/SWR import useSWR from 'swr' function Profile() { const

    { data, error, isLoading } = useSWR('/api/user', fetcher) if (error) return <div>failed to load </ div> if (isLoading) return <div>loading ...</ div> return <div>hello {data.name}! </ div> } SWR ͷྫ ӈͷΑ͏ʹ UI ίϯϙʔωϯτͰ௚઀ αʔόϦΫΤετΛʢΩϟογϡͷ֬ ೝʣͯ͠ UI ͱͯ͠දࣔ͢ΔྫͰ͢ɻ ͜ΕʹΑΓίϯϙʔωϯτͷϙʔλϏ ϦςΟੑΛ্͛ͯऔΓճ͠Λ͠΍͘͢ ͢ΔͨΊͷํ๏͕૿͑ͯདྷ͍ͯ·͢ɻ
  5. ঢ়ଶ؅ཧ άϩʔόϧεςʔτ جຊతʹ͸αʔόΛάϩʔόϧ εςʔτͱͯ͠ଊ͍͑ͯΔͷͰ ϦΫΤετσʔλͷΩϟογϡ ͕΄ͱΜͲղܾͯ͘͠ΕΔ͸ͣ Ͱ͢ɻ ͨͩ͠ɺෳ਺ͷεΫϦʔϯͳͲͰ ࢖ΘΕΔΑ͏ͳೝূτʔΫϯͳͲ ʹ͸

    Riverpod Ͱ؅ཧ͍ͯ͠·͢ɻ ϩʔΧϧεςʔτ εΫϦʔϯɺίϯϙʔωϯτ಺ Ͱ׬݁͢Δσʔλͷ؅ཧํ๏Ͱ ͢ɻΑ͋͘ΔྫͰ UI ʹදࣔ͢ ΔϩʔςΟϯάͷঢ়ଶͩͬͨ ΓɺϘλϯͷ༗ޮແޮͷ੾Γସ ͑༻ͩͬͨΓ͢Δ΋ͷ͸ Flutter Hooks Ͱ؅ཧ͍ͯ͠·͢ɻ αʔόϦΫΤετͱΩϟογϡ GraphQL Flutter Λར༻͍ͯ͠ ·͢ɻGraphQL Flutter ͸Ϩε ϙϯεσʔλͷΩϟογϡ΋͠ ͯ͘Ε·͢ɻ React Hooks ࢀߟ Recoil ࢀߟ TanStack/SWR ࢀߟ
  6. ϩʔΧϧεςʔτ Flutter Hooks ྫͷΑ͏ʹ͜ͷ΢ΟδΣοτ಺Ͱ ׬݁͢ΔΑ͏ͳσʔλͷ৔߹͸ Flutter Hooks ͷ useState(...) Λར༻

    ͯ͠؅ཧ͍ͯ͠·͢ɻ ͦΕҎ֎ʹ΋ useContext ΍ useCallback ͳͲ΋Α͘ར༻͍ͯ͠ ·͢ɻ @override Widget build(BuildContext context) { final isLoading = useState(false); // ... Կ͔ return Scaffold( body: Stack( children: [ const Text('Body'), if (isLoading.value) const Center( child: CircularProgressIndicator(), ), ], ), ); }
  7. άϩʔόϧεςʔτ جຊతʹ͸αʔόΛάϩʔόϧεςʔ τͱͯ͠ଊ͍͑ͯΔͷͰϦΫΤετ σʔλͷΩϟογϡ͕΄ͱΜͲղܾ͠ ͯ͘ΕΔ͸ͣͰ͢ɻ ͨͩ͠ɺෳ਺ͷεΫϦʔϯͳͲͰ࢖ΘΕ ΔΑ͏ͳೝূτʔΫϯͳͲʹ͸ Riverpod Ͱ؅ཧ͍ͯ͠·͢ɻ part

    'id_token_state.g.dart'; typedef IdToken = String; @Riverpod(keepAlive: true, dependencies: [firebaseAuth]) class IdTokenState extends _$IdTokenState { @override IdToken build() { return ''; } / / ॳظ஋͸ۭ Future<void> fetch() async { final user = ref.watch(firebaseAuthProvider).currentUser; if (user == null) return; update(await user.getIdToken()); } void update(String token) { if (state != token) state = token; } } @override Widget build(BuildContext context) { final idToken = ref.watch(idTokenStateProvider); // ... Կ͔ }
  8. αʔόϦΫΤετͱΩϟογϡ αʔόϦΫΤετͱΩϟογϡ͸ GraphQL Flutter ͕୲ͬͯ΋Β͍ͬͯ· ͢ɻαʔόϦΫΤετʹඞཁͳ৘ใ ʢFirebase Auth ͷ Id

    Token ͳͲʣҎ֎ ͸جຊతʹάϩʔόϧεςʔτͱͯ͠͸ ࣋ͨͳ͍Α͏ʹ͍ͯ͠·͢ɻ ར༻ϥΠϒϥϦɿgraphql_flutterɺgraphql_codegen
  9. GraphQL ͷઃܭʹ͍ͭͯ͸ Fragment Colocation Λجຊઃܭͱ͓ͯ͠ΓɺͦΕͧ ΕͷίϯϙʔωϯτͰඞཁͳσʔλ͸ Fragment ͱͯͦ͠ΕͧΕͰίϯϙʔωϯ τͱಉ༷ͷ৔ॴͰ .graphql

    ϑΝΠϧΛఆٛ ͍ͯ͠·͢ɻ Query ͸ը໘͔Βݺͼ·͢ɻ Home Screen User Component Feed Component query Home { user { ... UserParts } feed { ... FeedParts } } # Ϣʔβʔ৘ใ fragment UserParts on User { id } mutation CreateAccount { signUp { user { id } } } # ϑΟʔυ৘ใ fragment FeedParts on Feed { id title body }
  10. GraphQL Flutter ʹ͸ Flutter Hooks Λར༻ ͨ͠ػೳΛఏڙ͍ͯ͠ΔͷͰɺΑΓ TanStack Query ͷΑ͏ͳ͜ͱΛΠϝʔδ

    Ͱ͖Δͱࢥ͍·͢ɻ final readRespositoriesResult = useQuery( QueryOptions( document: gql(readRepositories), variables: { 'nRepositories': 50 }, pollInterval: const Duration(seconds: 10), ), ); final result = readRespositoriesResult.result; if (result.hasException) { return Text(result.exception.toString()); } if (result.isLoading) { return const Text('Loading'); } List? repositories = result.data?['viewer']?['repositories']?['nodes']; if (repositories == null) { return const Text('No repositories'); } return ListView.builder( itemCount: repositories.length, itemBuilder: (context, index) { final repository = repositories[index]; return Text(repository['name'] ?? ''); });
  11. σΟϨΫτϦߏ੒ શମͷσΟϨΫτϦߏ଄͸͜͏͍͏ܗͰ ఆ͍ٛͯ͠·͢ɻ࡞ΔʹͭΕͯۤ͘͠ͳͬ ͍ͯ͘Օॴ͸ਵ࣌ߟ͑௚͍ͯ͠·͢ɻ lib/ ├── data/ │ ├── network/

    │ └── system/ ├── foundation/ │ ├── extension/ # ֦ுؔ਺ │ └── firebase/ │ ├── auth/ # Firebase Auth ؔ࿈ │ └── messaging/ # Firebase Messaging ؔ࿈ ├── gen/ # FlutterGen ͳͲҰ෦ͷࣗಈੜ੒ϑΝΠϧ ├── l10n/ # Localization ؔ࿈ ├── route/ # auto_route ؔ࿈ ├── state/ # άϩʔόϧͷঢ়ଶ؅ཧؔ࿈ ├── ui/ # UI ؔ࿈ͷϞδϡʔϧʢGraphQL ͸֤ը໘Ͱఆٛʣ │ ├── screen/ │ │ └── home/ │ │ ├── home_screen.dart # ը໘ │ │ ├── home_screen_e2e.yaml # Maestro ͷϑΝΠϧ │ │ ├── home_screen_vrt.dart # Visual Regression Test ͷϑΝΠϧ │ │ ├── hook/ # ը໘ݻ༗ͷ Hooks │ │ │ └── use_update_home.dart │ │ ├── component/ # ը໘ݻ༗ͷίϯϙʔωϯτ │ │ │ ├── home_card.dart │ │ │ └── home_card_fragment.dart # ίϯϙʔωϯτͷ GraphQL ϑΝΠϧ │ │ └── top │ │ ├── home_top_screen_e2e.yaml │ │ └── home_top_screen.dart │ ├── theme/ # άϩʔόϧςʔϚઃఆ │ │ ├── app_theme.dart │ │ └── app_text.dart │ ├── hook/ # ൚༻తͳ Hooks │ │ ├── use_debounce.dart │ │ ├── use_debounce_test.dart │ │ ├── use_sign_in.dart │ │ ├── use_sign_in_test.dart │ │ ├── use_sign_out.dart │ │ └── use_sign_out_test.dart │ └── component/ # ൚༻ UI ίϯϙʔωϯτ │ ├── fab/ │ └── text/ └── use_case/