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

6dd0483f1353a4a359e92633cfd65c64?s=128

Daichi Furiya (Wasabeef)

March 23, 2022
Tweet

More Decks by Daichi Furiya (Wasabeef)

Other Decks in Programming

Transcript

  1. None
  2. ߱໼େ஍ גࣜձࣾαΠόʔΤʔδΣϯτ ϝσΟΞ౷ׅຊ෦ %FWFMPQFS1SPEVDUJWJUZࣨ XBTBCFFG@KQ 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 VUUFS@IPPLT ग़యɿ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 VUUFS@IPPLT ग़యɿ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 VUUFS@VTFϥΠϒϥϦΛར༻ͯ͠ΈΔ w SFBDU@VTFͷ'MVUUFS൛ w Λ௒͑Δ৭ʑͳϢʔεέʔεʹରԠͨ͠ΧελϜϑοΫू w ࣗ࡞ΧελϜϑοΫΛ࡞Δͱ͖ʹࢀߟʹͰ͖Δʢͱࢥ͏ʣ

  29. fl VUUFS@VTFϥΠϒϥϦΛར༻ͯ͠ΈΔ

  30. VTF& ff FDU0ODFΛར༻ͯ͠ΈΔ w fl VUUFS@VTFʹ͓͍ͯ࠷΋୯७ͳ࣮૷ 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 VUUFS@VTFʹ͓͍ͯ࠷΋୯७ͳ࣮૷ 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 ಺෦Ͱ͸DPOOFDUJWJUZ@QMVTͱ͍͏ϥΠϒϥϦΛ࢖ͬͯ୺ ຤ͷωοτϫʔΫঢ়گΛऔಘ͍ͯ͠Δ w ࣗ෼Ͱ࣮૷͢Δͱඇಉظॲཧͷ੍ޚͳͲ͕ඞཁ͕ͩɺ͜ ͷΧελϜϑοΫͰ͸ར༻ଆ͸γϯϓϧʹ͍ͯ͠Δ class Sample extends HookWidget

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

  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 VUUFS@IPPLT@UFTU

  44. 'MVUUFS)PPLTͷ-JOU w fl VUUFS@IPPLT@MJOU@QMVHJOΛར༻ͯ͠ΈΔ w FTMJOUQMVHJOSFBDUIPPLTͷ'MVUUFS൛ IUUQTHJUIVCDPNNKIE fl VUUFS@IPPLT@MJOU@QMVHJO

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

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