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

Flutter Hooks を使ったアプリ開発 / App Development with the Flutter Hooks

Flutter Hooks を使ったアプリ開発 / App Development with the Flutter Hooks

CyberAgent Developer Conference 2022

Daichi Furiya (Wasabeef)

March 23, 2022
Tweet

More Decks by Daichi Furiya (Wasabeef)

Other Decks in Programming

Transcript

  1. None
  2. ߱໼େ஍ גࣜձࣾαΠόʔΤʔδΣϯτ ϝσΟΞ౷ׅຊ෦ %FWFMPQFS1SPEVDUJWJUZࣨ [email protected] XBTBCFFG (PPHMF%FWFMPQFST&YQFSU

  3. "HFOEB wαΠόʔΤʔδΣϯτͷ'MVUUFS࠾༻ࣄྫ w'MVUUFS)PPLTΛ࢖ͬͨΞϓϦ։ൃ w 'MVUUFS)PPLTͱ͸ʁ w 4UBUFGVM8JEHFUͷϥΠϑαΠΫϧΛར༻ͨ͠৔߹ w 'MVUUFS)PPLTΛجຊΛཧղ͢Δ w

    'MVUUFS)PPLTͷޮՌతͳར༻๏ wࠓޙͷల๬
  4. αΠόʔΤʔδΣϯτͷ'MVUUFS࠾༻ࣄྫ

  5. 'MVUUFSͷ࠾༻ࣄྫ ग़యɿIUUQTXXXDZCFSBHFOUDPKQUFDIJOGPJOGPEFUBJMJE

  6. 'MVUUFS)PPLTΛ࢖ͬͨΞϓϦ։ൃ

  7. 'MVUUFS)PPLTͱ͸ʁ

  8. 'MVUUFS)PPLTͱ͸ʁ ग़యɿIUUQTHJUIVCDPNSSPVTTFM(JU fl [email protected] ग़యɿIUUQTSFBDUKTPSHEPDTIPPLTJOUSPIUNM w 3FBDU)PPLTͷ'MVUUFS൛Ͱจ๏΋࢖͍ํ΋΄΅ಉ͡΋ͷ

  9. 4UBUFGVM8JEHFUͷ ϥΠϑαΠΫϧΛ ར༻ͨ͠৔߹

  10. class CountPage extends StatefulWidget { @override State createState() => _CountState();

    } class _CountState extends State<CountPage> { int count = 0; @override void initState() { / ** ॳظԽ **/ } @override void dispose() { /** ഁغ **/ } void setCount(int value) => setState(() = > count = value); @override Widget build(BuildContext context) { return TextButton( child: Text("Count is $count"), onPressed: () => setCount(count + 1), ); } } w γεςϜͷঢ়ଶͳͲʹΑͬͯಈతʹ มԽΛ͢Δখ͞ͳϥΠϑαΠΫϧΛ ΋ͬͨ΢ΟδΣοτ w *NBHFɺ5FYU'PSN'JFME΍)FSPͳ Ͳ͕4UBUFGVM8JEHFUͷαϒΫϥε 4UBUFGVM8JEHFUͷઆ໌
  11. class CountPage extends StatefulWidget { @override State createState() => _CountState();

    } class _CountState extends State<CountPage> { int count = 0; @override void initState() { / ** ॳظԽ **/ } @override void dispose() { /** ഁغ **/ } void setCount(int value) => setState(() = > count = value); @override Widget build(BuildContext context) { return TextButton( child: Text("Count is $count"), onPressed: () => setCount(count + 1), ); } } 4UBUFGVM8JEHFUΛ࢖͏ʹ͸جຊతʹೋͭͷ ΫϥεΛ࡞Δඞཁ͕͋Δ w 4UBUFGVM8JEHFUΛܧঝͨ͠$PVOU1BHF w 4UBUF5Λܧঝͨ͠@$PVOU4UBUF 4UBUFGVM8JEHFUͷઆ໌
  12. class CountPage extends StatefulWidget { @override State createState() => _CountState();

    } class _CountState extends State<CountPage> { int count = 0; @override void initState() { / ** ॳظԽ **/ } @override void dispose() { /** ഁغ **/ } void setCount(int value) => setState(() = > count = value); @override Widget build(BuildContext context) { return TextButton( child: Text("Count is $count"), onPressed: () => setCount(count + 1), ); } } 4UBUFGVM8JEHFUͷઆ໌ 4UBUFGVM8JEHFUΛ࢖͏ʹ͸جຊతʹೋͭͷ ΫϥεΛ࡞Δඞཁ͕͋Δ w 4UBUFGVM8JEHFUΛܧঝͨ͠$PVOU1BHF w 4UBUF5Λܧঝͨ͠@$PVOU4UBUF
  13. class CountPage extends StatefulWidget { @override State createState() => _CountState();

    } class _CountState extends State<CountPage> { int count = 0; @override void initState() { / ** ॳظԽ **/ } @override void dispose() { /** ഁغ **/ } void setCount(int value) => setState(() = > count = value); @override Widget build(BuildContext context) { return TextButton( child: Text("Count is $count"), onPressed: () => setCount(count + 1), ); } } 4UBUFGVM8JEHFUͷઆ໌ JOJU4UBUFɿॳظԽͷॲཧ EJTQPTFɿഁغͷॲཧ TFU4UBUFɿݺͿ͜ͱͰঢ়ଶ͕มԽͨ͜͠ͱ Λ௨஌ͯ͠ϦϏϧυ͕૸Δ
  14. 4UBUFGVM8JEHFUͰ࣮૷ͨ͠৔߹ͷ՝୊ w ঢ়ଶΛอ࣋͢ΔΫϥεΛ৽ͨʹ࡞Βͳ͍ͱ͍͚ͳ͍ w ෳࡶͳϩδοΫΛؚΉঢ়ଶΛอ͍࣋ͨ͠৔߹ʹ͸ϩδοΫ ͱ΢ΟδΣοτΛ෼཭Ͱ͖͍ͯͳ͍ w ίʔυͷ࠶ར༻͕ѱ͍ w ςετ͕ॻ͖ʹ͍͘

  15. 'MVUUFS)PPLTͷ جຊΛཧղ͢Δ

  16. 'MVUUFS)PPLTͰԿ͕ղܾͰ͖Δ͔ ग़యɿIUUQTHJUIVCDPNSSPVTTFM(JU fl [email protected] ग़యɿIUUQTSFBDUKTPSHEPDTIPPLTJOUSPIUNM w એݴత6*ͰΫϥΠΞϯτΛ࣮૷্͍ͯ͘͠ͰɺϩδοΫͱ ΢ΟδΣοτʢίϯϙʔωϯτʣͷ෼཭ΛϝϯςφϯεੑΛอ ͪͭͭҡ࣋͢Δͷ͕೉͘͠ɺͦΕΛղܾ͢ΔػೳΛఏڙ͢Δ w

    ίϯϙʔωϯτΛͪΌΜͱؔ਺ͱͯ͠ѻ͏ͨΊ w ΫϥεͷఆٛΛݮΒ͢ʢγϯλοΫεγϡΨʔʣͨΊ w 'MVUUFSͷ΢ΟδΣοτ͸සൟʹ࠶ඳը͕࣮ߦ͞ΕΔͨΊॏ͍ ԋࢉ΍ෳࡶͳॲཧΛ͚͞ΕΔΑ͏ͳػೳΛఏڙ͢Δ w ಉ͡ೖྗσʔλͷ৔߹ʹ͸݁ՌΛΩϟογϡ͢Δ
  17. VTF4UBUFΛཧղ͢Δ VTF4UBUF͸'MVUUFS)PPLTΛར༻͢ΔͳΒඞͣར༻͢Δ Ͱ͋Ζ͏جຊతͳϑοΫͰ͢ʢ಺෦࣮૷͸7BMVF/PUJGJFSʣ ར༻͢Δʹ֮͋ͨͬͯ͑Δ͜ͱ؆୯ͰVTF4UBUF 5 Ͱॳظ ஋Λ༩͑ɺDPVOUWBMVFͷ஋Λมߋ͢Δ͜ͱͰ࠶ඳը // ॳظԽ final

    count = useState(0); // ஋ͷߋ৽Λ࠶ඳը count.value = 3;
  18. VTF4UBUFΛཧղ͢Δ ঢ়ଶͷ؅ཧΛ͢ΔͨΊʹϞόΠϧΞϓϦ։ൃͷΞʔΩςΫ νϟͰΑ͘ฉ͘Α͏ͳ7JFX.PEFM΍4UPSFΛ༻ҙ͢Δ΄ ͲͰ΋ͳ͍৔߹ʹར༻͢Δ͜ͱͰ͖Δ ྫ͑͹ɺϘλϯͷ&OBCMFE%JTBCMFEͷঢ়ଶͷอ࣋͸Θ͟ Θ͟ΫϥεΛ࡞Δ·Ͱ΋ͳ͘ɺͦͷ΢ΟδΣοτͰอ࣋͢ ΔͳͲ

  19. VTF4UBUFΛཧղ͢Δ class CountPage extends HookWidget { @override Widget build(BuildContext context)

    { final count = useState(0); return TextButton( onPressed: () { count.value ++ ; }, child: Text("Count is ${count.value}"), ); } } class CountPage extends StatefulWidget { @override State createState() => _CountState(); } class _CountState extends State<CountPage> { int count = 0; void setCount(int value) => setState(() = > count = value); @override Widget build(BuildContext context) { return TextButton( child: Text("Count is $count"), onPressed: () => setCount(count + 1), ); } } 4UBUFGVM8JEHFU VTF4UBUF େ͖ͳҧ͍͸4UBUFΛܧঝͨ͠Ϋϥε͕ඞ ཁͩͬͨ΋ͷ͕ͳ͘ͳΓVTF4UBUF 5 ʹॳ ظ஋Λ༩͑Δ͚ͩʹͳ͍ͬͯΔ
  20. VTF4UBUFΛཧղ͢Δ class CountPage extends HookWidget { @override Widget build(BuildContext context)

    { final count = useState(0); return TextButton( onPressed: () { count.value + + ; }, child: Text("Count is ${count.value}"), ); } }
  21. VTF& ff FDUΛཧղ͢Δ ؆୯ͳ΢ΟδΣοτͷϥΠϑαΠΫϧͰॲཧ͕ඞཁͩͬͨ ৔߹ʹ͸VTF&GGFDUΛ࢖͏ 
 ʢ΢ΟδΣοτੜ੒࣌ʹॳظԽ΍ഁغΛ͍ͨ͠৔߹ͳͲʣ class _CountState extends

    State<CountPage> { ɹ // . .. @override void initState() { / ** ॳظԽ **/ } @override void dispose() { /** ഁغ **/ } } ɹ // . .. } 4UBUFGVM8JEHFUͷJOJU4UBUFEJQPTF૬౰
  22. VTF& ff FDUΛཧղ͢Δ class CountPage extends HookWidget { @override Widget

    build(BuildContext context) { useEffect(() => { / / ॳظԽ final subscription = source.subscribe(id); return () => { // ഁغ subscription.unsubscribe(id); }; }, [id]); return // Widget . .. } } 8JEHFUͷCVJME಺ͰVTF&GGFDUͷୈҰҾ ਺ʹΫϩʔδϟΛ౉͠ɺͦͷΫϩʔδϟͷ SFUVSO࣌ʹഁغ࣌ͷॲཧΛॻ͘ VTF&GGFDUͷୈೋҾ਺ʹ͸ॳظԽΛϏϧυ࣌ ʹຖճ࣮ߦ͞Εͳ͍Α͏ʹΩʔͱͳΔΦϒ δΣΫτΛ౉͢ඞཁ͕͋Δ
  23. VTF& ff FDUͷୈೋҾ਺͸ॏཁ class CountPage extends HookWidget { @override Widget

    build(BuildContext context) { useEffect(() => { / / ᶃ ID ͕มߋ͞ΕΔͨͼʹݺͼग़͠ }, [id]); useEffect(() => { / / ᶄ ຖճݺͼग़͠ }); useEffect(() => { / / ᶅ ࠷ॳͷҰճ͚ͩݺͼग़͠ }, const []); return // Widget . .. } }
  24. VTF"OJNBUJPO$POUSPMMFSΛར༻ͯ͠ΈΔ class Example extends StatefulWidget { final Duration duration; const

    Example({Key? key, required this.duration}) : super(key: key); @override _ExampleState createState() => _ExampleState(); } class _ExampleState extends State<Example> with SingleTickerProviderStateMixin { AnimationController? _controller; @override void initState() { super.initState(); _controller = AnimationController(vsync: this, duration: widget.duration); } @override void didUpdateWidget(Example oldWidget) { super.didUpdateWidget(oldWidget); if (widget.duration != oldWidget.duration) { _controller!.duration = widget.duration; } } @override void dispose() { _controller!.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container(); } } 4UBUFGVM8JEHFU 'MVUUFSͰΞχϝʔγϣϯΛ4UBUFGVM8JEHFU Ͱ࣮૷͠Α͏ͱ͢Δͱঢ়ଶ؅ཧͷίʔυΛΫ ϥεʹ͚ͩͰ͜Ε͚ͩඞཁʹͳΓͦͷଟ͕͘ ࢖͍ճ͠Ͱ͖ͳ͍ίʔυʹͳΔ ˞৑௕ͳίʔυΛݮΒ͢ͱ͍͏໨త͚ͩͰ͋ Ε͹%BSUʹ΋.JYJO͕͋ΔͷͰͦΕͰڞ௨ Խ͢Δ͜ͱ΋Ͱ͖Δ
  25. VTF"OJNBUJPO$POUSPMMFSΛར༻ͯ͠ΈΔ class Example extends HookWidget { const Example({required this.duration}); final

    Duration duration; @override Widget build(BuildContext context) { final controller = useAnimationController(duration: duration); return Container(); } } class Example extends StatefulWidget { final Duration duration; const Example({Key? key, required this.duration}) : super(key: key); @override _ExampleState createState() => _ExampleState(); } class _ExampleState extends State<Example> with SingleTickerProviderStateMixin { AnimationController? _controller; @override void initState() { super.initState(); _controller = AnimationController(vsync: this, duration: widget.duration); } @override void didUpdateWidget(Example oldWidget) { super.didUpdateWidget(oldWidget); if (widget.duration != oldWidget.duration) { _controller!.duration = widget.duration; } } @override void dispose() { _controller!.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container(); } } 4UBUFGVM8JEHFU VTF"OJNBUJPO$POUSPMMFS VTF"OJNBUJPO$POUSPMMFSΛ࢖͏͜ͱͰ৑௕ ͳίʔυྔ͸ݮΒ͢͜ͱ͕Ͱ͖ɺར༻ଆͰͷ ίετΛԼ͛Δ͜ͱ͕Ͱ͖Δ
  26. 'MVUUFS)PPLTͷ ޮՌతͳར༻๏

  27. ΧελϜϑοΫΛ࡞੒͢Δ w ؔ਺໊ʹ͸VTF999ͱ͍͏໊લΛ͚ͭΔ w ࠷ॳ͸VTF4UBUF΍VTF& ff FDUΛ૊Έ߹Θ ࣮ͤͯ૷ͯ͠ΈΔ VoidCallback useUpdate()

    { final attempt = useState(0); return () => attempt.value ++ ; } class Sample extends HookWidget { @override Widget build(BuildContext context) { final update = useUpdate(); return Column( children: [ ElevatedButton( onPressed: () => update(), child: const Text("Update"), ), ] ); } } VTF6QEBUF 4BNQMF
  28. fl [email protected]ϥΠϒϥϦΛར༻ͯ͠ΈΔ w [email protected]ͷ'MVUUFS൛ w Λ௒͑Δ৭ʑͳϢʔεέʔεʹରԠͨ͠ΧελϜϑοΫू w ࣗ࡞ΧελϜϑοΫΛ࡞Δͱ͖ʹࢀߟʹͰ͖Δʢͱࢥ͏ʣ

  29. fl [email protected]ϥΠϒϥϦΛར༻ͯ͠ΈΔ

  30. VTF& ff FDU0ODFΛར༻ͯ͠ΈΔ w fl [email protected]ʹ͓͍ͯ࠷΋୯७ͳ࣮૷ w VTF& ff FDUͷୈೋҾ਺Λলུ͢ΔͨΊͷΧελϜϑοΫ

    useEffect(() => { // ࠷ॳͷҰճ͚ͩݺͼग़͠ }, const []); void useEffectOnce(Dispose? Function() effect) { return useEffect(effect, const []); } VTF&GGFDU VTF&GGFDU0ODFͷ࣮૷
  31. VTF& ff FDU0ODFΛར༻ͯ͠ΈΔ w fl [email protected]ʹ͓͍ͯ࠷΋୯७ͳ࣮૷ w VTF& ff FDUͷୈೋҾ਺Λলུ͢ΔͨΊͷΧελϜϑοΫ

    useEffect(() => { // ࠷ॳͷҰճ͚ͩݺͼग़͠ }, const []); void useEffectOnce(Dispose? Function() effect) { return useEffect(effect, const []); } VTF&GGFDU VTF&GGFDU0ODFͷ࣮૷
  32. w ΞϓϦཁ݅ͰԿඵޙʹॲཧΛ࣮ߦ͍ͤͨ͞৔߹ w VTF5JNFPVUVTF5JNFPVU'OΛ࢖͏͜ͱͰࢦఆͷ࣌ؒܦա ޙʹϦϏϧυ΍ΫϩʔδϟΛ࣮ߦ͢Δ͜ͱ͕Ͱ͖Δ class Sample extends HookWidget {

    @override Widget build(BuildContext context) { final timeout = useTimeout(const Duration(seconds: 3)); return Column( children: [ Text("isReady ?: ${timeout.isReady}"), ElevatedButton( onPressed: () => timeout.reset(), child: const Text("Reset"), ), ], ); } } VTF5JNFPVUΛར༻ͯ͠ΈΔ
  33. w ಺෦Ͱ͸[email protected]ͱ͍͏ϥΠϒϥϦΛ࢖ͬͯ୺ ຤ͷωοτϫʔΫঢ়گΛऔಘ͍ͯ͠Δ w ࣗ෼Ͱ࣮૷͢Δͱඇಉظॲཧͷ੍ޚͳͲ͕ඞཁ͕ͩɺ͜ ͷΧελϜϑοΫͰ͸ར༻ଆ͸γϯϓϧʹ͍ͯ͠Δ class Sample extends HookWidget

    { @override Widget build(BuildContext context) { final networkState = useNetworkState(); return Column( children: [ Text( "Network: ${networkState.connectivityResult}"), ], ); } } VTF/FUXPSL4UBUFΛར༻ͯ͠ΈΔ
  34. fl [email protected] IUUQTHJUIVCDPNXBTBCFFG fl [email protected]

  35. ΧελϜϑοΫͷςετ w 'MVUUFS)PPLT5FTUJOH-JCSBSZΛར༻ͯ͠ΈΔ w SFBDUIPPLTUFTUJOHMJCSBSZͷ'MVUUFS൛

  36. ϥΠϒϥϦΛར༻͠ͳ͍৔߹ testWidgets('usePrevious', (tester) async { await tester.pumpWidget( HookBuilder(builder: (context) {

    usePrevious(42); return const SizedBox(); }), ); await tester.pumpWidget( HookBuilder(builder: (context) { usePrevious(21); return const SizedBox(); }), ); final element = tester.element(find.byType(HookBuilder)); expect( element .toDiagnosticsNode(style: DiagnosticsTreeStyle.offstage) .toStringDeep(), equalsIgnoringHashCodes( 'HookBuilder\n' ' │ usePrevious: 42\n' ' └SizedBox(renderObject: RenderConstrainedBox#00000)\n', ), ); }); VTF1SFWJPVT͸'MVUUFS)PPLTʹඪ ४Ͱؚ·Ε͍ͯΔ༩͑ͨ஋ͷҰͭલͷ ঢ়ଶΛอ࣋͢ΔΧελϜϑοΫ ͜ͷϑοΫΛςετॻ͘৔߹ʹ͸࠷௿ Ͱ΋͜Ε͚ͩͷίʔυྔͰ͢
  37. testWidgets('usePrevious', (tester) async { / / ... await tester.pumpWidget( HookBuilder(builder:

    (context) { usePrevious(42); return const SizedBox(); }), ); / / ... }); ϥΠϒϥϦΛར༻͠ͳ͍৔߹ গ͠ࡉ͔͘આ໌͍ͯ͘͠ͱɺ QVNQ8JEHFUͱ͍͏ςετ༻΢Ο δΣοτͷঢ়ଶΛ؅ཧ͍ͯ͠Δؔ਺ʹ )PPL#VJMEFSΛ౉ͯ͠ɺͦͷதͰΧε λϜϑοΫΛ࢖͏ඞཁ͕͋Δ
  38. testWidgets('usePrevious', (tester) async { / / ... await tester.pumpWidget( HookBuilder(builder:

    (context) { usePrevious(21); return const SizedBox(); }), ); / / ... }); ϥΠϒϥϦΛར༻͠ͳ͍৔߹ ΋͏Ұ౓ߋ৽͠ͳ͍ͱ͍͚ͳ͍ͷͰɺ ઌ΄Ͳ͸͕ͩͬͨࠓճ͸Λ౉ ͍ͯ͠Δ
  39. testWidgets('usePrevious', (tester) async { // .. . final element =

    tester.element(find.byType(HookBuilder)); expect( element .toDiagnosticsNode(style: DiagnosticsTreeStyle.offstage) .toStringDeep(), equalsIgnoringHashCodes( 'HookBuilder\n' ' │ usePrevious: 42\n' ' └SizedBox(renderObject: RenderConstrainedBox#00000)\n', ), ); // .. . }); VTF1SFWJPVTͱ͍͏Ұͭલͷ஋Λอ࣋ ͢ΔͷͰ࠷ॳʹ౉͕ͨ͠ݱࡏอ࣋ ͍ͯ͠Δ஋ͱͳΔ ͜ΕΛνΣοΫ͢ΔͨΊʹςετ΢Ο δΣοτͷϊʔυΛจࣈྻ͔Βϋο γϡίʔυͰൺֱ͍ͯ͠Δ ϥΠϒϥϦΛར༻͠ͳ͍৔߹
  40. testWidgets('usePrevious', (tester) async { await tester.pumpWidget( HookBuilder(builder: (context) { usePrevious(42);

    return const SizedBox(); }), ); await tester.pumpWidget( HookBuilder(builder: (context) { usePrevious(21); return const SizedBox(); }), ); final element = tester.element(find.byType(HookBuilder)); expect( element .toDiagnosticsNode(style: DiagnosticsTreeStyle.offstage) .toStringDeep(), equalsIgnoringHashCodes( 'HookBuilder\n' ' │ usePrevious: 42\n' ' └SizedBox(renderObject: RenderConstrainedBox#00000)\n', ), ); }); ϥΠϒϥϦΛར༻͠ͳ͍৔߹
  41. testWidgets('usePrevious', (tester) async { final result = await buildHook( (value)

    = > usePrevious(value), initialProps: 42, ); await result.rebuild(21); expect(result.current, 42); }); testWidgets('usePrevious', (tester) async { await tester.pumpWidget( HookBuilder(builder: (context) { usePrevious(42); return const SizedBox(); }), ); await tester.pumpWidget( HookBuilder(builder: (context) { usePrevious(21); return const SizedBox(); }), ); final element = tester.element(find.byType(HookBuilder)); expect( element .toDiagnosticsNode(style: DiagnosticsTreeStyle.offstage) .toStringDeep(), equalsIgnoringHashCodes( 'HookBuilder\n' ' │ usePrevious: 42\n' ' └SizedBox(renderObject: RenderConstrainedBox#00000)\n', ), ); }); ར༻͠ͳ͍ ར༻͢Δ ΧελϜϑοΫͷঢ়ଶΛߋ৽͢ΔͨΊʹ UFTUFSQVNQ8JEHFUʹ)PPL#VJMEFSΛຖ ճ౉͍ͯͨ͠΋ͷΛলུͰ͖ɺFYQFDU࣌ͷ ঢ়ଶऔಘ΋γϯϓϧʹॻ͚Δ ϥΠϒϥϦΛར༻͢Δ৔߹
  42. testWidgets('usePrevious', (tester) async { final result = await buildHook( (value)

    = > usePrevious(value), initialProps: 42, ); await result.rebuild(21); expect(result.current, 42); }); 'MVUUFS)PPLT5FTUJOH-JCSBSZΛར༻ͨ͠৔ ߹͸ଟ͘ͷ৑௕ίʔυΛ࡟ݮ͢Δ͜ͱ͕Ͱ͖Δ CVJME)PPLɿͷΫϩʔδϟʹΧελϜϑοΫͷ ݺͼग़͠Λॻ͖ɺୈೋҾ਺ʹॳظ஋Λ༩͑Δ͜ ͱ͕Ͱ͖Δ SFCVJMEɿCVJME)PPLͰੜ੒͞ΕͨΫϥεͰ஋ Λߋ৽͠ϦϏϧυͰ͖Δ DVSSFOUɿอ͍࣋ͯ͠Δ஋ΛऔಘͰ͖Δ ϥΠϒϥϦΛར༻͢Δ৔߹
  43. 'MVUUFS)PPLT5FTUJOH-JCSBSZ IUUQTHJUIVCDPNXBTBCFFG fl [email protected]@UFTU

  44. 'MVUUFS)PPLTͷ-JOU w fl [email protected]@[email protected]Λར༻ͯ͠ΈΔ w FTMJOUQMVHJOSFBDUIPPLTͷ'MVUUFS൛ IUUQTHJUIVCDPNNKIE fl [email protected]@[email protected]

  45. final variable1 = callSomething(); final variable2 = callSomething(); // ෆඞཁ·ͨ͸ෆ଍͍ͯ͠ΔΩʔ

    useEffect(() { print(variable1); }, [variable2]); // ϑοΫΛ৚݅෼ذͷதʹೖΕͳ͍ if (flag) { final variable = useState('hello'); } ϑοΫʹ͸͍͔ͭ͘ͷϧʔϧ͕͋Γ·͢ ྫ w ΧελϜϑοΫͷؔ਺໊ʹ͸VTF999 ͱ͍͏໊લΛ͚ͭΔ ɾϑοΫΛ৚݅෼ذʹೖΕͳ͍ ͜ͷ1MVHJOΛ࢖͏͜ͱͰόάΛ๷͙ͱڞ ʹϨϏϡʔͷίετͳͲͷԼ͛Δ fl [email protected]@[email protected]Λར༻ͯ͠ΈΔ
  46. ࠓޙͷల๬

  47. ࠓޙͷల๬ w )PPLTʹΑΔੈք؍Λ'MVUUFSք۾ʹਁಁ͍͖͍ͤͯͨ͞ w ੵۃతʹ'MVUUFSΑΓ΋ྺ࢙ͷ͋Δ3FBDU͔ΒऔΓೖΕ͍ͯ͘ w ྺ࢙͸3FBDUʼ'MVUUFSʼ+FUQBDL$PNQPTF4XJGU6*ͳͷͰ 'MVUUFSͷ஌ݟΛ+FUQBDL$PNQPTFͳͲʹ΋స༻͍ͯ͘͠ w 3FBDU2VFSZʹΑΔγϯϓϧͳઃܭΛ'MVUUFSʹ΋औΓೖΕ͍ͨ

    w ΞϓϦΞʔΩςΫνϟʹ࣌ؒΛ͔͚ͳ͍ੈք؍ͷ044࡞Δ w 3FDPJMɺ.77.ͳͲͷֶशʹ࣌ؒΛ࢖Θͣ؆୯ͳΞϓϦΛ؆୯ʹ࡞Δ ग़యɿIUUQTXXXJSBTVUPZBDPN