Flutter: ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๊ฑฐ๋‚˜ ๋„ˆ๋ฌด ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2020๋…„ 03์›” 02์ผ  ยท  420์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: flutter/flutter

.

ํ›„ํฌ ๊ด€๋ จ ํ† ๋ก  #25280

TL;DR: State ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•˜๊ณ  ๊นŠ์ด ์ค‘์ฒฉ๋œ build ๋ฉ”์„œ๋“œ๋กœ ๋๋‚˜๊ฑฐ๋‚˜ ์—ฌ๋Ÿฌ ์œ„์ ฏ์— ๋…ผ๋ฆฌ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฏน์Šค์ธ์ด๋‚˜ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ

์—ฌ๋Ÿฌ StatefulWidget ์—์„œ State ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํ•ด๋‹น ๋…ผ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์˜์กดํ•˜๋Š” ํ•œ ๋งค์šฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์˜ˆ๋Š” TextEditingController ( AnimationController , ์•”์‹œ์  ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ)๋ฅผ ๋งŒ๋“œ๋Š” ๋…ผ๋ฆฌ์ž…๋‹ˆ๋‹ค. ํ•ด๋‹น ๋…ผ๋ฆฌ๋Š” ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

  • State ์— ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    dart TextEditingController controller;
  • ์ž ์žฌ์ ์œผ๋กœ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ(์ผ๋ฐ˜์ ์œผ๋กœ initState ๋‚ด๋ถ€) ์ƒ์„ฑ:
    dart <strong i="25">@override</strong> void initState() { super.initState(); controller = TextEditingController(text: 'Hello world'); }
  • State ๊ฐ€ ํ๊ธฐ๋  ๋•Œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค.
    dart <strong i="30">@override</strong> void dispose() { controller.dispose(); super.dispose(); }
  • build ๋‚ด๋ถ€์˜ ํ•ด๋‹น ๋ณ€์ˆ˜๋กœ ์›ํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • (์„ ํƒ ์‚ฌํ•ญ) debugFillProperties ์— ํ•ด๋‹น ์†์„ฑ์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
    dart void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('controller', controller)); }

์ด๊ฒƒ์€ ๊ทธ ์ž์ฒด๋กœ ๋ณต์žกํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ํ•ด๋‹น ์ ‘๊ทผ ๋ฐฉ์‹์„ ํ™•์žฅํ•  ๋•Œ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.
์ผ๋ฐ˜์ ์ธ Flutter ์•ฑ์—๋Š” ์ˆ˜์‹ญ ๊ฐœ์˜ ํ…์ŠคํŠธ ํ•„๋“œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ด ๋…ผ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ณต์ œ๋ฉ๋‹ˆ๋‹ค.

์ด ๋…ผ๋ฆฌ๋ฅผ ๋ชจ๋“  ๊ณณ์— ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์œผ๋ฉด "์ž‘๋™"ํ•˜์ง€๋งŒ ์ฝ”๋“œ์— ์•ฝ์ ์ด ์ƒ๊น๋‹ˆ๋‹ค.

  • ๋‹จ๊ณ„ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆฌ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค(์˜ˆ dispose ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ์žŠ์Œ)
  • ์ฝ”๋“œ์— ๋งŽ์€ ๋…ธ์ด์ฆˆ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋ฏน์‹  ๋ฌธ์ œ

์ด ๋…ผ๋ฆฌ๋ฅผ ์ธ์ˆ˜๋ถ„ํ•ดํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ์‹œ๋„๋Š” mixin์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

mixin TextEditingControllerMixin<T extends StatefulWidget> on State<T> {
  TextEditingController get textEditingController => _textEditingController;
  TextEditingController _textEditingController;

  <strong i="11">@override</strong>
  void initState() {
    super.initState();
    _textEditingController = TextEditingController();
  }

  <strong i="12">@override</strong>
  void dispose() {
    _textEditingController.dispose();
    super.dispose();
  }

  <strong i="13">@override</strong>
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty('textEditingController', textEditingController));
  }
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

class Example extends StatefulWidget {
  <strong i="17">@override</strong>
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example>
    with TextEditingControllerMixin<Example> {
  <strong i="18">@override</strong>
  Widget build(BuildContext context) {
    return TextField(
      controller: textEditingController,
    );
  }
}

๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์—๋Š” ๋‹ค๋ฅธ ๊ฒฐํ•จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • mixin์€ ํด๋ž˜์Šค๋‹น ํ•œ ๋ฒˆ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. StatefulWidget ์—ฌ๋Ÿฌ ๊ฐœ์˜ TextEditingController ํ•„์š”ํ•˜๋ฉด ๋” ์ด์ƒ ๋ฏน์Šค์ธ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ๋ฏน์Šค์ธ์— ์˜ํ•ด ์„ ์–ธ๋œ "์ƒํƒœ"๋Š” ๋‹ค๋ฅธ ๋ฏน์Šค์ธ ๋˜๋Š” State ์ž์ฒด์™€ ์ถฉ๋Œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ๋งํ•˜๋ฉด ๋‘ ๊ฐœ์˜ ๋ฏน์Šค์ธ์ด ๊ฐ™์€ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฉค๋ฒ„๋ฅผ ์„ ์–ธํ•˜๋ฉด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
    ์ตœ์•…์˜ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์ถฉ๋Œํ•˜๋Š” ๊ตฌ์„ฑ์›์ด ๊ฐ™์€ ์œ ํ˜•์ด๋ฉด ์ž๋™์œผ๋กœ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

์ด๋กœ ์ธํ•ด ๋ฏน์Šค์ธ์€ ์ด์ƒ์ ์ด์ง€ ์•Š๊ณ  ์ง„์ •ํ•œ ์†”๋ฃจ์…˜์ด ๋˜๊ธฐ์—๋Š” ๋„ˆ๋ฌด ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค.

"๋นŒ๋”" ํŒจํ„ด ์‚ฌ์šฉ

๋˜ ๋‹ค๋ฅธ ํ•ด๊ฒฐ์ฑ…์€ StreamBuilder & co์™€ ๋™์ผํ•œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” TextEditingControllerBuilder ์œ„์ ฏ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์šฐ๋ฆฌ์˜ build ๋ฉ”์†Œ๋“œ์—์„œ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์œ„์ ฏ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค.

class TextEditingControllerBuilder extends StatefulWidget {
  const TextEditingControllerBuilder({Key key, this.builder}) : super(key: key);

  final Widget Function(BuildContext, TextEditingController) builder;

  <strong i="12">@override</strong>
  _TextEditingControllerBuilderState createState() =>
      _TextEditingControllerBuilderState();
}

class _TextEditingControllerBuilderState
    extends State<TextEditingControllerBuilder> {
  TextEditingController textEditingController;

  <strong i="13">@override</strong>
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(
        DiagnosticsProperty('textEditingController', textEditingController));
  }

  <strong i="14">@override</strong>
  void dispose() {
    textEditingController.dispose();
    super.dispose();
  }

  <strong i="15">@override</strong>
  Widget build(BuildContext context) {
    return widget.builder(context, textEditingController);
  }
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

class Example extends StatelessWidget {
  <strong i="19">@override</strong>
  Widget build(BuildContext context) {
    return TextEditingControllerBuilder(
      builder: (context, controller) {
        return TextField(
          controller: controller,
        );
      },
    );
  }
}

์ด๊ฒƒ์€ ๋ฏน์Šค์ธ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉ๋ฒ•์ด ๋งค์šฐ ์žฅํ™ฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋‹จ์ผ ๋ณ€์ˆ˜ ์„ ์–ธ์— ๋Œ€ํ•ด ํšจ๊ณผ์ ์œผ๋กœ 4์ค„์˜ ์ฝ”๋“œ + 2๋‹จ๊ณ„ ๋“ค์—ฌ์“ฐ๊ธฐ์ž…๋‹ˆ๋‹ค.
    ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ์—๋Š” ๋”์šฑ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. TextEditingControllerBuilder ๋‚ด๋ถ€์—

    <strong i="28">@override</strong>
    Widget build(BuildContext context) {
    return TextEditingControllerBuilder(
      builder: (context, controller1) {
        return TextEditingControllerBuilder(
          builder: (context, controller2) {
            return Column(
              children: <Widget>[
                TextField(controller: controller1),
                TextField(controller: controller2),
              ],
            );
          },
        );
      },
    );
    }
    

    ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ ๋‘ ๊ฐœ์˜ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ธฐ ์œ„ํ•œ ๋งค์šฐ ๋“ค์—ฌ์“ฐ๊ธฐ๋œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

  • ์ถ”๊ฐ€ State ๋ฐ Element ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์•ฝ๊ฐ„์˜ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต TextEditingController ์™ธ๋ถ€ build .
    State ์ˆ˜๋ช… ์ฃผ๊ธฐ๊ฐ€ ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ผ๋ถ€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•ด GlobalKey ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

    class Example extends StatefulWidget {
    <strong i="43">@override</strong>
    _ExampleState createState() => _ExampleState();
    }
    
    class _ExampleState extends State<Example> {
    final textEditingControllerKey =
        GlobalKey<_TextEditingControllerBuilderState>();
    
    <strong i="44">@override</strong>
    void didUpdateWidget(Example oldWidget) {
      super.didUpdateWidget(oldWidget);
    
      if (something) {
        textEditingControllerKey.currentState.textEditingController.clear();
      }
    }
    
    <strong i="45">@override</strong>
    Widget build(BuildContext context) {
      return TextEditingControllerBuilder(
        key: textEditingControllerKey,
        builder: (context, controller) {
          return TextField(controller: controller);
        },
      );
    }
    }
    
P5 crowd framework passed first triage proposal new feature

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

React ๊ด€์ ์—์„œ ๋ช‡ ๊ฐ€์ง€ ์ƒ๊ฐ์„ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ๋“ค์ด ๊ด€๋ จ์ด ์—†๋‹ค๋ฉด ์šฉ์„œํ•˜์ง€๋งŒ Hooks์— ๋Œ€ํ•ด ์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜๋Š”์ง€ ๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ํ™•์‹คํžˆ "์ˆจ๊ธฐ๊ธฐ"์ž…๋‹ˆ๋‹ค. ๋˜๋Š” ์–ด๋–ป๊ฒŒ ๋ณด๋Š๋ƒ์— ๋”ฐ๋ผ ์บก์Šํ™”ํ•˜์‹ญ์‹œ์˜ค. ํŠนํžˆ, ๊ทธ๊ฒƒ๋“ค์€ ์ง€์—ญ ์ƒํƒœ์™€ ํšจ๊ณผ๋ฅผ ์บก์Šํ™”ํ•ฉ๋‹ˆ๋‹ค(์ €๋Š” ์šฐ๋ฆฌ์˜ "ํšจ๊ณผ"๊ฐ€ "์ผํšŒ์šฉ"๊ณผ ๊ฐ™์€ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค). "์•”์‹œ์„ฑ"์€ ํ˜ธ์ถœ๋˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ์— ์ˆ˜๋ช…์„ ์ž๋™์œผ๋กœ ์ฒจ๋ถ€ํ•œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋‚ด์žฌ์„ฑ์€ ๋ชจ๋ธ์— ๋‚ด์žฌ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ธ์ˆ˜๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ์Šค๋ ˆ๋“œ๋˜๋Š” ๊ฒƒ์„ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ ์ž์ฒด์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ Hook, ๊ฐ ๊ธฐ๋ณธ Hook์— ์ด๋ฅด๊ธฐ๊นŒ์ง€ ๋ง์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์ด ์‹œ๋„๋Ÿฝ๊ณ  ์‹ค์ œ๋กœ ์œ ์šฉํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ Component๋ฅผ ์•”์‹œ์  ์ „์—ญ ์ƒํƒœ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ VM์˜ throw errorHandlerFrame ๊ฐ€ ์ฝ”๋“œ์—์„œ catch ๋ธ”๋ก์„ ์œ„์ชฝ์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ข‹์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€์— ์•”์‹œ์  ์€๋‹‰ ์ƒํƒœ๊ฐ€ ์žˆ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ข‹์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๊นŒ? ๊ทธ๋Ÿฌ๋‚˜ React์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ปดํฌ๋„ŒํŠธ์˜ ์š”์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์€ (UI ํŠธ๋ฆฌ์˜ ์œ„์น˜์— ํ•ด๋‹นํ•˜๋Š”) ์ˆ˜๋ช…์ด ์—ฐ๊ฒฐ๋œ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ ์ž์ฒด๊ฐ€ ์ƒํƒœ์™€ ๊ด€๋ จํ•˜์—ฌ ๋ฐœํŒ์ด ์•„๋‹Œ ์ด์œ ๋Š” ์ž„์˜์˜ ์ฝ”๋“œ์—์„œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ UI ์ฝ”๋“œ์˜ ์ปจํ…์ŠคํŠธ์— ๋‚จ์•„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜๋ช…์ด ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ๊ตฌ์„ฑ ์š”์†Œ ํ˜•ํƒœ์ธ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ƒํƒœ+ํšจ๊ณผ์™€ ๋‚˜๋ฌด ์œ„์น˜์— ์—ฐ๊ฒฐ๋œ ์ˆ˜๋ช…์ด๋ผ๋Š” ๋‘ ๊ฐ€์ง€ ๋Šฅ๋ ฅ์„ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์ฒซ ๋ฒˆ์งธ ๋Šฅ๋ ฅ์ด ๊ทธ ์ž์ฒด๋กœ ์œ ์šฉํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ์ฝ”๋“œ๋ฅผ ์บก์Šํ™”ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ ์œ ์šฉํ•˜๋“ฏ์ด ํŠธ๋ฆฌ์— ์ƒˆ ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ์ƒํƒœ+ํšจ๊ณผ ๋ฒˆ๋“ค์„ ์บก์Šํ™”(๋ฐ ์žฌ์‚ฌ์šฉ)ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ณธ ์š”์†Œ๊ฐ€ ๋ถ€์กฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ Hooks์ž…๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ = ํ›„ํฌ + ๋ฐ˜ํ™˜๋œ UI.

๋‚ด๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ปจํ…์ŠคํŠธ ์ƒํƒœ๋ฅผ ์ˆจ๊ธฐ๋Š” ์ž„์˜์˜ ํ•จ์ˆ˜๋Š” ๋ฌด์„ญ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ๋ฆฐํ„ฐ๋ฅผ ํ†ตํ•ด ๊ทœ์น™์„ ์‹œํ–‰ํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. Hook์—๋Š” "์ƒ‰์ƒ" ์ด ์žˆ์Šต๋‹ˆ๋‹ค. Hook์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๋„ Hook์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ฆฐํ„ฐ๋Š” ์ปดํฌ๋„ŒํŠธ๋‚˜ ๋‹ค๋ฅธ Hooks๋งŒ์ด Hooks๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ด์ œ ๊ตฌ์„ฑ ์š”์†Œ ์ž์ฒด๋ณด๋‹ค ๋” ์•”์‹œ์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ปจํ…์ŠคํŠธ UI ์ƒํƒœ๋ฅผ ์ˆจ๊ธฐ๋Š” ์ž„์˜ ํ•จ์ˆ˜์˜ ๋ฌธ์ œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋…์ ์œผ๋กœ ์šฐ๋ฆฌ๋Š” Hook ํ˜ธ์ถœ์„ ์ผ๋ฐ˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๋ณด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. useState() ๋Š” ๊ตฌ๋ฌธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ use State() ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์–ธ์–ด ๊ธฐ๋Šฅ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํšจ๊ณผ ์ถ”์  ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ์–ธ์–ด์—์„œ ๋Œ€์ˆ˜ ํšจ๊ณผ๊ฐ€ ์žˆ๋Š” Hooks์™€ ๊ฐ™์€ ๊ฒƒ์„ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ ๊ทธ๊ฒƒ๋“ค ์€ ์ผ๋ฐ˜ ํ•จ์ˆ˜์ด์ง€๋งŒ State๋ฅผ "์‚ฌ์šฉ"ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์€ ํƒ€์ž… ์„œ๋ช…์˜ ์ผ๋ถ€๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ React ์ž์ฒด๋ฅผ ์ด ํšจ๊ณผ์— ๋Œ€ํ•œ "์ฒ˜๋ฆฌ์ž"๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด์จŒ๋“  ์ด๊ฒƒ์€ ๋งค์šฐ ์ด๋ก ์ ์ด์ง€๋งŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์˜ ๊ด€์ ์—์„œ ์„ ํ–‰ ๊ธฐ์ˆ ์„ ์ง€์ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

์‹ค์šฉ์ ์ธ ์ธก๋ฉด์—์„œ ์—ฌ๊ธฐ์—๋Š” ๋ช‡ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ์งธ, Hooks๊ฐ€ React์˜ "์ถ”๊ฐ€" API๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ์ ์— ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์€์ด ์‹œ์ ์—์„œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ์œ„ํ•œ API ๋ฐ˜์‘์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๋“ค์ด ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์œผ๋กœ์„œ ๊ทธ๋‹ค์ง€ ๋งค๋ ฅ์ ์ด์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ‹€๋ฆผ์—†์ด ๋‹ค๋ฅธ ์ „์ฒด ํŒจ๋Ÿฌ๋‹ค์ž„์„ ๊ฐ€์ง„ Flutter์— ๋Œ€ํ•ด ๊ทธ๋“ค์ด ์ •๋ง๋กœ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ๋“ค์ด ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์— ๊ด€ํ•ด์„œ๋Š”, ํ•ต์‹ฌ ๊ธฐ๋Šฅ์€ ์ƒํƒœ+์œ ํšจ ๋กœ์ง์„ ์บก์Šํ™”ํ•œ ๋‹ค์Œ ์ผ๋ฐ˜ ํ•จ์ˆ˜ ๊ตฌ์„ฑ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋Š” ๊ตฌ์„ฑํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— useState() ์™€ ๊ฐ™์€ ์ผ๋ถ€ ํ›„ํฌ ์ถœ๋ ฅ์„ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉ์ž ์ •์˜ useGesture(state) ์— ๋Œ€ํ•œ ์ž…๋ ฅ์œผ๋กœ ์ „๋‹ฌํ•œ ๋‹ค์Œ ์ด๋ฅผ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž ์ •์˜ useSpring(gesture) ์ž…๋ ฅ์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ์ฐจ ๊ฐ’์„ ์ œ๊ณตํ•˜๋Š” ๋ฐ๋ชจ ์™€ Hooks๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๊ฐ„๋žตํ•˜๊ฒŒ ์š”์•ฝํ•œ ๊ธฐ์‚ฌ ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ์ƒ์šฉ๊ตฌ๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ƒํƒœ ์ €์žฅ ์บก์Šํ™”๋œ ๋กœ์ง์˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋™์ ์œผ๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๋Šฅ๋ ฅ์— ๊ด€ํ•œ

์ด๊ฒƒ์ด ์กฐ๊ธˆ์ด๋ผ๋„ ๋„์›€์ด ๋˜์—ˆ๋Š”์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์— ๋Œ€ํ•œ ๊ด€์ ์„ ์กฐ๊ธˆ์ด๋ผ๋„ ๋ฒ—์–ด๋‚˜๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.
๋‹ค๋ฅธ ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  420 ๋Œ“๊ธ€

cc @dnfield @Hixie
์š”์ฒญํ•œ ๋Œ€๋กœ ํ›„ํฌ์— ์˜ํ•ด ํ•ด๊ฒฐ๋œ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

ํ”„๋ ˆ์ž„์›Œํฌ ๋‚ด์—์„œ ์ด ์ž‘์—…์„ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค๋ ค๋Š” ์‹œ๋„๊ฐ€ ์‹ค์ œ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ๊ฐํ•ด์•ผ ํ•˜๋Š” ๋ณต์žก์„ฑ์„ ์ˆจ๊ธธ๊นŒ๋ด ๊ฑฑ์ •๋ฉ๋‹ˆ๋‹ค.

์ผ์ข…์˜ abstract class Disposable ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ํ˜•์‹์˜ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž‘์„ฑ์ž์—๊ฒŒ ์ด ์ค‘ ์ผ๋ถ€๊ฐ€ ๋” ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌํ•œ ๊ฒฝ์šฐ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋” ๊ฐ„๋‹จํ•œ ํด๋ž˜์Šค๋ฅผ ๋” ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class AutomaticDisposingState<T> extends State<T> {
  List<Disposable> _disposables;

  void addDisposable(Disposable disposable) {
    assert(!_disposables.contains(disposable));
    _disposables.add(disposable);
  }

  <strong i="8">@override</strong>
  void dispose() {
    for (final Disposable disposable in _disposables)
      disposable.dispose();
    super.dispose();
  }
}

๋ฐ˜๋ณต๋˜๋Š” ๋ช‡ ์ค„์˜ ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ๋””๋ฒ„๊ทธ ์†์„ฑ์— ๋Œ€ํ•ด ์œ ์‚ฌํ•œ ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‘˜ ๋ชจ๋‘๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ํด๋ž˜์Šค๋„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธฐํ™” ์ƒํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<strong i="12">@override</strong>
void initState() {
  super.initState();
  controller = TextEditingController(text: 'Hello world');
  addDisposable(controller);
  addProperty('controller', controller);
}

์ผํšŒ์šฉ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ด๋Ÿฌํ•œ ์ž…๋ ฅ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

ํ”„๋ ˆ์ž„์›Œํฌ ๋‚ด์—์„œ ์ด ์ž‘์—…์„ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค๋ ค๋Š” ์‹œ๋„๊ฐ€ ์‹ค์ œ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ๊ฐํ•ด์•ผ ํ•˜๋Š” ๋ณต์žก์„ฑ์„ ์ˆจ๊ธธ๊นŒ๋ด ๊ฑฑ์ •๋ฉ๋‹ˆ๋‹ค.

์œ„์ ฏ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ๊ฐํ•ด์•ผ ํ•˜๋Š” ๋ณต์žก์„ฑ์„ ์ˆจ๊น๋‹ˆ๋‹ค.
๊ทธ๊ฒŒ ์ •๋ง ๋ฌธ์ œ์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ธ์ˆ˜๋ถ„ํ•ดํ•˜๋Š” ๊ฒƒ์€ ์‚ฌ์šฉ์ž์˜ ๋ชซ์ž…๋‹ˆ๋‹ค.


๋ฌธ์ œ๋Š” ์ผํšŒ์šฉํ’ˆ๋งŒ์˜ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋ฌธ์ œ์˜ ์—…๋ฐ์ดํŠธ ๋ถ€๋ถ„์„ ์žŠ์–ด๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ์Šคํ…Œ์ด์ง€ ๋กœ์ง์€ didChangeDependencies ๋ฐ didUpdateWidget๊ณผ ๊ฐ™์€ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์˜์กดํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ช‡ ๊ฐ€์ง€ ๊ตฌ์ฒด์ ์ธ ์˜ˆ:

  • didChangeDependencies ๋‚ด๋ถ€์— ๋…ผ๋ฆฌ๊ฐ€ ์žˆ๋Š” SingleTickerProviderStateMixin .
  • super.build(context) ์— ์˜์กดํ•˜๋Š” AutomaticKeepAliveClientMixin

์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ ค๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋งŽ์€ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ŠคํŠธ๋ฆผ๋นŒ๋”
  • TweenAnimationBuilder
    ...

์ด๊ฒƒ๋“ค์€ ์—…๋ฐ์ดํŠธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ ์ƒํƒœ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๋“ค์€ "๋นŒ๋”"๋ถ€๋ถ„์—์„œ ์–ธ๊ธ‰ ํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ๊ฒช๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋งŽ์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด Stackoverflow์—์„œ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ ์ค‘ ํ•˜๋‚˜๋Š” "๋ณ€๊ฒฝ ์‹œ ๊ฒฝ๋กœ ํ‘ธ์‹œ"์™€ ๊ฐ™์€ ๋ถ€์ž‘์šฉ์— ๋Œ€ํ•ด StreamBuilder ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ์‚ฌ๋žŒ๋“ค์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ถ๊ทน์ ์œผ๋กœ ๊ทธ๋“ค์˜ ์œ ์ผํ•œ ํ•ด๊ฒฐ์ฑ…์€ StreamBuilder๋ฅผ "๊บผ๋‚ด๋Š”" ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

  • ์œ„์ ฏ์„ ์ƒํƒœ ์ €์žฅ์œผ๋กœ ๋ณ€ํ™˜
  • initState+didUpdateWidget+didChangeDependencies์—์„œ ์ˆ˜๋™์œผ๋กœ ์ŠคํŠธ๋ฆผ์„ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ŠคํŠธ๋ฆผ์ด ๋ณ€๊ฒฝ๋  ๋•Œ didChangeDependencies/didUpdateWidget์— ๋Œ€ํ•œ ์ด์ „ ๊ตฌ๋… ์ทจ์†Œ
  • ํ๊ธฐ ์‹œ ๊ตฌ๋… ์ทจ์†Œ

๊ทธ๊ฒƒ์€ _๋งŽ์€ ์ž‘์—…_์ด๋ฉฐ ํšจ๊ณผ์ ์œผ๋กœ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ

์—ฌ๋Ÿฌ StatefulWidget ์—์„œ State ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํ•ด๋‹น ๋…ผ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์˜ˆ๋Š” TextEditingController ( AnimationController , ์•”์‹œ์  ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ)์„ ๋งŒ๋“œ๋Š” ๋…ผ๋ฆฌ์ž…๋‹ˆ๋‹ค. ํ•ด๋‹น ๋…ผ๋ฆฌ๋Š” ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

  • State ์— ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    dart TextEditingController controller;
  • ์ž ์žฌ์ ์œผ๋กœ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ(์ผ๋ฐ˜์ ์œผ๋กœ initState ๋‚ด๋ถ€) ์ƒ์„ฑ:
    dart <strong i="19">@override</strong> void initState() { super.initState(); controller = TextEditingController(text: 'Hello world'); }
  • State ๊ฐ€ ํ๊ธฐ๋  ๋•Œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค.
    dart <strong i="24">@override</strong> void dispose() { controller.dispose(); super.dispose(); }
  • build ๋‚ด๋ถ€์˜ ํ•ด๋‹น ๋ณ€์ˆ˜๋กœ ์›ํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • (์„ ํƒ ์‚ฌํ•ญ) debugFillProperties ์— ํ•ด๋‹น ์†์„ฑ์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
    dart void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('controller', controller)); }

์ด๊ฒƒ์€ ๊ทธ ์ž์ฒด๋กœ ๋ณต์žกํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ํ•ด๋‹น ์ ‘๊ทผ ๋ฐฉ์‹์„ ํ™•์žฅํ•  ๋•Œ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.
์ผ๋ฐ˜์ ์ธ Flutter ์•ฑ์—๋Š” ์ˆ˜์‹ญ ๊ฐœ์˜ ํ…์ŠคํŠธ ํ•„๋“œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ด ๋…ผ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ณต์ œ๋ฉ๋‹ˆ๋‹ค.

์ด ๋…ผ๋ฆฌ๋ฅผ ๋ชจ๋“  ๊ณณ์— ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์œผ๋ฉด "์ž‘๋™"ํ•˜์ง€๋งŒ ์ฝ”๋“œ์— ์•ฝ์ ์ด ์ƒ๊น๋‹ˆ๋‹ค.

  • ๋‹จ๊ณ„ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆฌ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค(์˜ˆ dispose ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ์žŠ์Œ)
  • ์ฝ”๋“œ์— ๋งŽ์€ ๋…ธ์ด์ฆˆ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์™œ ๋ฌธ์ œ์ธ์ง€ ์ดํ•ดํ•˜๊ธฐ๊ฐ€ ์ •๋ง ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์ €๋Š” Flutter ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŽ์ด ์ž‘์„ฑํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ํฐ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๊นŒ? ์ตœ์•…์˜ ๊ฒฝ์šฐ์—๋„ ์†์„ฑ์„ ์„ ์–ธํ•˜๊ณ , ์ดˆ๊ธฐํ™”ํ•˜๊ณ , ํ๊ธฐํ•˜๊ณ , ๋””๋ฒ„๊ทธ ๋ฐ์ดํ„ฐ์— ๋ณด๊ณ ํ•˜๋Š” ๋ฐ 4์ค„์ด ์†Œ์š”๋ฉ๋‹ˆ๋‹ค(์‹ค์ œ๋กœ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ์™€ ๋™์ผํ•œ ์ค„์—์„œ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ์ ์Šต๋‹ˆ๋‹ค. ์•ฑ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋””๋ฒ„๊ทธ ์†์„ฑ์— ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ์ด๋Ÿฌํ•œ ๊ฐ์ฒด ์ค‘ ๋‹ค์ˆ˜๋Š” ํ๊ธฐํ•ด์•ผ ํ•˜๋Š” ์ƒํƒœ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์†์„ฑ ์œ ํ˜•๋ณ„ ๋ฏน์Šค์ธ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋” ํŒจํ„ด์ด ์ข‹์ง€ ์•Š๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค(๋ง ๊ทธ๋Œ€๋กœ ์œ„์—์„œ ์„ค๋ช…ํ•œ ์ตœ์•…์˜ ์‹œ๋‚˜๋ฆฌ์˜ค์™€ ๋™์ผํ•œ ์ˆ˜์˜ ๋ผ์ธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค).

NNBD(ํŠนํžˆ late final ํ•˜์—ฌ ์ดˆ๊ธฐํ™”์ž๊ฐ€ this ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก )๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

typedef Initializer<T> = T Function();
typedef Disposer<T> = void Function(T value);

mixin StateHelper<T extends StatefulWidget> on State<T> {
  bool _active = false;
  List<Property<Object>> _properties = <Property<Object>>[];

  <strong i="8">@protected</strong>
  void registerProperty<T>(Property<T> property) {
    assert(T != Object);
    assert(T != dynamic);
    assert(!_properties.contains(property));
    _properties.add(property);
    if (_active)
      property._initState();
  }

  <strong i="9">@override</strong>
  void initState() {
    _active = true;
    super.initState();
    for (Property<Object> property in _properties)
      property._initState();
  }

  <strong i="10">@override</strong>
  void dispose() {
    for (Property<Object> property in _properties)
      property._dispose();
    super.dispose();
    _active = false;
  }

  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    for (Property<Object> property in _properties)
      property._debugFillProperties(properties);
  }
}

class Property<T> {
  Property(this.owner, this.initializer, this.disposer, [ this.debugName ]) {
    owner.registerProperty(this);
  }

  final StateHelper<StatefulWidget> owner;
  final Initializer<T> initializer;
  final Disposer<T> disposer;
  final String debugName;

  T value;

  void _initState() {
    if (initializer != null)
      value = initializer();
  }

  void _dispose() {
    if (disposer != null)
      disposer(value);
    value = null;
  }

  void _debugFillProperties(DiagnosticPropertiesBuilder properties) {
    properties.add(DiagnosticsProperty(debugName ?? '$T property', value));
  }
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  <strong i="14">@override</strong>
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with StateHelper<MyHomePage> {
  late final Property<int> _counter = Property<int>(this, null, null);
  late final Property<TextEditingController> _text = Property<TextEditingController>(this,
    () => TextEditingController(text: 'button'),
    (TextEditingController value) => value.dispose(),
  );

  void _incrementCounter() {
    setState(() {
      _counter.value += 1;
    });
  }

  <strong i="15">@override</strong>
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the ${_text.value.text} this many times:',
            ),
            Text(
              '${_counter.value}',
              style: Theme.of(context).textTheme.headline4,
            ),
            TextField(
              controller: _text.value,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

์ •๋ง ์ƒํ™ฉ์ด ๋‚˜์•„์ง€๋Š” ๊ฒƒ ๊ฐ™์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์•„์ง 4์ค„์ž…๋‹ˆ๋‹ค.

์œ„์ ฏ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ๊ฐํ•ด์•ผ ํ•˜๋Š” ๋ณต์žก์„ฑ์„ ์ˆจ๊น๋‹ˆ๋‹ค.

๊ทธ๋“ค์€ ๋ฌด์—‡์„ ์ˆจ๊ธฐ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

๋ฌธ์ œ๋Š” ์ค„์˜ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ด ์ค„์ด ๋ฌด์—‡์ธ์ง€์ž…๋‹ˆ๋‹ค.

StreamBuilder ๋Š” stream.listen + setState + subscription.close ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ StreamBuilder ์ž‘์„ฑ์€ ๋ฐ˜์˜ ์—†์ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ ๊ณผ์ •์—์„œ ์‹ค์ˆ˜๊ฐ€ ์žˆ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ "์ŠคํŠธ๋ฆผ์„ ์ „๋‹ฌํ•˜๊ณ  ๊ทธ๊ฒƒ์œผ๋กœ๋ถ€ํ„ฐ ์œ„์ ฏ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ"์ž…๋‹ˆ๋‹ค.

์ˆ˜๋™์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ๋Š” ํ›จ์”ฌ ๋” ๋งŽ์€ ์ƒ๊ฐ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • ์ŠคํŠธ๋ฆผ์ด ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์žŠ์—ˆ๋‹ค๋ฉด ๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ตฌ๋… ์ข…๋ฃŒ๋ฅผ ์žŠ์œผ์…จ๋‚˜์š”? ๋˜ ๋‹ค๋ฅธ ๋ฒ„๊ทธ
  • ๊ตฌ๋…์— ์–ด๋–ค ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ? ํ•ด๋‹น ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ…Œ์ŠคํŠธ๋Š” ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ํ…Œ์ŠคํŠธ๋ฅผ ๋ณต์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? StreamBuilder ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ŠคํŠธ๋ฆผ์„ ์ˆ˜์‹ ํ•˜๊ธฐ ์œ„ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์ค‘๋ณต๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๊ฐ€ ํ•ญ์ƒ ์ˆ˜๋™์œผ๋กœ ์ž‘์„ฑํ•˜๋ฉด ์‹ค์ˆ˜๋ฅผ ๋ฒ”ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ•œ ๋ฒˆ์— ๋‘ ๊ฐœ์˜ ์ŠคํŠธ๋ฆผ์„ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒฝ์šฐ ์ฝ”๋“œ๋ฅผ ์˜ค์—ผ์‹œํ‚ค๋Š” ๋งค์šฐ ์œ ์‚ฌํ•œ ์ด๋ฆ„์„ ๊ฐ€์ง„ ์—ฌ๋Ÿฌ ๋ณ€์ˆ˜๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ํ˜ผ๋™์„ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋“ค์€ ๋ฌด์—‡์„ ์ˆจ๊ธฐ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

  • FutureBuilder/StreamBuilder๋Š” ์ˆ˜์‹  ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ˆจ๊ธฐ๊ณ  ํ˜„์žฌ ์Šค๋ƒ…์ƒท์ด ๋ฌด์—‡์ธ์ง€ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.
    ๋‘๊ฐœ์˜ ์ „ํ™˜ ๋กœ์ง Future ์—†๋Š”์„ ๊ณ ๋ คํ•˜์—ฌ๋„ ๋งค์šฐ ๋ณต์žก subscription.close() .
  • AnimatedContainer๋Š” ์ด์ „ ๊ฐ’๊ณผ ์ƒˆ ๊ฐ’ ์‚ฌ์ด์— ํŠธ์œˆ์„ ๋งŒ๋“œ๋Š” ๋…ผ๋ฆฌ๋ฅผ ์ˆจ๊น๋‹ˆ๋‹ค.
  • Listview๋Š” "์œ„์ ฏ์ด ํ‘œ์‹œ๋˜๋Š” ๋Œ€๋กœ ๋งˆ์šดํŠธ"์˜ ๋…ผ๋ฆฌ๋ฅผ ์ˆจ๊น๋‹ˆ๋‹ค.

์•ฑ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋””๋ฒ„๊ทธ ์†์„ฑ์— ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋“ค์€ debugFillProperties ๋ฉ”์„œ๋“œ๋ฅผ ์œ ์ง€ ๊ด€๋ฆฌํ•˜๋Š” ๋ณต์žก์„ฑ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๊ฐ€ ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ "๋ชจ๋“  ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ์ƒํƒœ ์†์„ฑ์„ Flutter์˜ devtool์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๊นŒ?"๋ผ๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๋“ค์ด ์˜ˆ๋ผ๊ณ  ๋งํ•  ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค

๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด React์˜ devtool๊ณผ ๊ฐ™์€ ์ง„์ •ํ•œ ๋™๋“ฑ๋ฌผ์— ๋Œ€ํ•œ ์—ด๋ง์„ ๋‚˜์—๊ฒŒ ํ‘œํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค. Flutter์˜ devtool์€ ์•„์ง ์—†์Šต๋‹ˆ๋‹ค.
React์—์„œ ์šฐ๋ฆฌ๋Š” ์œ„์ ฏ์˜ ๋ชจ๋“  ์ƒํƒœ์™€ ๊ทธ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๊ณ  ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š๊ณ  ํŽธ์ง‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์‚ฌ๋žŒ๋“ค์€ provider + ๋‚ด ๋‹ค๋ฅธ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ „์ฒด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์ƒํƒœ๊ฐ€ ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š๊ณ ๋„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋งํ–ˆ์„ ๋•Œ ๋งค์šฐ ๋†€๋ž์Šต๋‹ˆ๋‹ค( ์ด ์„ฑ๊ฐ€์‹  devtool ๋ฒ„๊ทธ ๋ชจ๋“ˆ๋กœ ).

๋‚˜๋Š” FutureBuilder์˜ ์—ด๋ ฌํ•œ ํŒฌ์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์ธ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด Future๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•  ๋•Œ๋ฅผ ์ƒ๊ฐํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋งŽ์€ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ์ง€์›์„ ์ค‘๋‹จํ•˜๋Š” ๊ฒƒ์€ ๋ฌด๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. StreamBuilder๋Š” ๊ดœ์ฐฎ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์ŠคํŠธ๋ฆผ ์ž์ฒด๊ฐ€ ๋„ˆ๋ฌด ๋ณต์žกํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค(์œ„์˜ ์ฃผ์„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด).

Tween ์ƒ์„ฑ์˜ ๋ณต์žก์„ฑ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

ListView๋Š” ์œ„์ ฏ์ด ํ‘œ์‹œ๋˜๋Š” ๋Œ€๋กœ ํƒ‘์žฌํ•˜๋Š” ๋…ผ๋ฆฌ๋ฅผ ์‹ค์ œ๋กœ ์ˆจ๊ธฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. API์˜ ํฐ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ์ค„์˜ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ด ์ค„์ด ๋ฌด์—‡์ธ์ง€์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์—ฌ๊ธฐ์˜ ์šฐ๋ ค๋ฅผ ์ •๋ง๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ๋‹ค. ๋ผ์ธ์€ ๋‹จ์ˆœํ•œ ์ƒ์šฉ๊ตฌ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ์‚ฌ๋ฌผ์„ ์„ ์–ธํ•˜๊ณ  ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ์‚ฌ๋ฌผ์„ ํ๊ธฐํ•ฉ๋‹ˆ๋‹ค. ํ–‰์˜ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๋ฌด์—‡์ด ๋ฌธ์ œ์ธ๊ฐ€?

FutureBuilder๊ฐ€ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์ œ์—์„œ ์กฐ๊ธˆ ๋ฒ—์–ด๋‚˜๊ธด ํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ ์ค‘์— Flutter๊ฐ€ ๋ช‡ ์ดˆ๋งˆ๋‹ค ๊ฐ€์งœ ํ•ซ ๋ฆฌ๋กœ๋“œ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ FutureBuilder, ํ‚ค ๋“ฑ์˜ ์˜ค์šฉ์„ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค.

Tween ์ƒ์„ฑ์˜ ๋ณต์žก์„ฑ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

ListView๋Š” ์œ„์ ฏ์ด ํ‘œ์‹œ๋˜๋Š” ๋Œ€๋กœ ํƒ‘์žฌํ•˜๋Š” ๋…ผ๋ฆฌ๋ฅผ ์‹ค์ œ๋กœ ์ˆจ๊ธฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. API์˜ ํฐ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์š”์ ์€ ํ›„ํฌ๊ฐ€ ํ•˜๋Š” ์ผ์€ TweenAnimationBuilder / AnimatedContainer /... ํ•˜๋Š” ๊ฒƒ๊ณผ ์™„์ „ํžˆ ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— "๋…ผ๋ฆฌ๋ฅผ ์ˆจ๊น๋‹ˆ๋‹ค"๋กœ ํ›„ํฌ์™€ ๊ฐ™์€ ๊ฒƒ์„ ๋น„ํŒํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋…ผ๋ฆฌ๋Š” ์ˆจ๊ฒจ์ ธ ์žˆ์ง€ ์•Š๋‹ค

๊ฒฐ๊ตญ ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ์ข‹์€ ๋น„๊ต๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜์—๋Š” ์•”์‹œ์  ๋Œ€ ๋ช…์‹œ์  ๊ฐœ๋…์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์•”์‹œ์  ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ๋‹จ์ˆœ์„ฑ, ๊ตฌ์„ฑ ๊ฐ€๋Šฅ์„ฑ ๋ฐ ๊ฐ€๋…์„ฑ ๋•Œ๋ฌธ์— ์‚ฌ๋ž‘๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
๋ช…์‹œ์  ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ๋” ์œ ์—ฐํ•˜์ง€๋งŒ ๋” ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฐœ๋…์„ ์ŠคํŠธ๋ฆผ ์ˆ˜์‹ ์œผ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ StreamBuilder ๋Š” _์•”์‹œ์  ์ˆ˜์‹ _์ธ ๋ฐ˜๋ฉด stream.listen ๋Š” _๋ช…์‹œ์ _์ž…๋‹ˆ๋‹ค.

๋” ๊ตฌ์ฒด์ ์œผ๋กœ ๋งํ•˜๋ฉด StreamBuilder ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ŠคํŠธ๋ฆผ์ด ๋ณ€๊ฒฝ๋˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ _cannot_ ์žŠ๊ฑฐ๋‚˜ ๊ตฌ๋…์„ ์ข…๋ฃŒํ•˜๋Š” ๊ฒƒ์„ ์žŠ์Šต๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ StreamBuilder ํ•จ๊ป˜ ๊ฒฐํ•ฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

stream.listen ๋Š” ์•ฝ๊ฐ„ ๊ณ ๊ธ‰์Šค๋Ÿฝ๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

๋นŒ๋”๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋‹จ์ˆœํ™”ํ•˜๋Š” ๋ฐ ๊ฐ•๋ ฅํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์ด์ „์— ๋™์˜ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ Builder ํŒจํ„ด์€ ์ด์ƒ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์“ฐ๊ธฐ์™€ ์‚ฌ์šฉ ๋ชจ๋‘ ์žฅํ™ฉํ•ฉ๋‹ˆ๋‹ค.
์ด ๋ฌธ์ œ์™€ ํ›„ํฌ๊ฐ€ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์€ *Builders์˜ ๋Œ€์ฒด ๊ตฌ๋ฌธ์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด flutter_hooks ๋Š” FutureBuilder ๋ฐ StreamBuilder ์™€ ์™„์ „ํžˆ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

Widget build(context) {
  final AsyncSnapshot<T> snapshot = useStream(stream);
}

๊ณ„์†ํ•ด์„œ AnimatedContainer & ์œ ์‚ฌ๋Š” useAnimatedSize / useAnimatedDecoractedBox / ...๋กœ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

double opacity;

Widget build(context) {
  final double animatedOpacity = useAnimatedDouble(opacity, duration: Duration(milliseconds: 200));
  return Opacity(
    opacity: animatedOpacity,
    child: ...,
  );
}

๋‚ด ์š”์ ์€ ํ›„ํฌ์™€ ๊ฐ™์€ ๊ฒƒ์„ "๋…ผ๋ฆฌ๋ฅผ ์ˆจ๊น๋‹ˆ๋‹ค"๋กœ ๋น„ํŒํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ์ฃผ์žฅ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ฃผ์žฅ์€ " ๊ฐœ๋ฐœ์ž๊ฐ€ ์ƒ๊ฐํ•ด์•ผ ํ•  ๋…ผ๋ฆฌ ๋Š” ๊ฒƒ์ด๋‹ค .

๊ฐœ๋ฐœ์ž๋“ค์ด ์ƒ๊ฐํ•ด์•ผ ํ•  ๊ทธ๋Ÿฌํ•œ ๋…ผ๋ฆฌ์˜ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

๋ˆ„๊ฐ€ TextEditingController๋ฅผ ์†Œ์œ ํ•˜๊ณ  ์žˆ๋Š”์ง€(๋ˆ„๊ฐ€ ์ƒ์„ฑํ•˜๊ณ  ๋ˆ„๊ฐ€ ํ๊ธฐํ•˜๋Š”์ง€)์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ์ฝ”๋“œ์ฒ˜๋Ÿผ?

Widget build(context) {
  final controller = useTextEditingController();
  final focusNode = useFocusNode();
}

ํ›„ํฌ๊ฐ€ ์ƒ์„ฑํ•˜๊ณ  ํ๊ธฐํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์— ๋Œ€ํ•ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋„ค, ๋งž์Šต๋‹ˆ๋‹ค. ๊ทธ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ „ํ˜€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ์–ดํœ˜ ๋ฒ”์œ„๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ์ง€์†๋ฉ๋‹ˆ๊นŒ? ๊ตญ๊ฐ€์˜ ์ˆ˜๋ช…? ๋‹ค๋ฅธ ๊ฒƒ? ๋ˆ„๊ฐ€ ๊ทธ๊ฒƒ์„ ์†Œ์œ ํ•ฉ๋‹ˆ๊นŒ? ๋‹ค๋ฅธ ์‚ฌ๋žŒ์—๊ฒŒ ์–‘๋„ํ•˜๋ฉด ์†Œ์œ ๊ถŒ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ด ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ์ฝ”๋“œ ์ž์ฒด์—์„œ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ท€ํ•˜์˜ ์ฃผ์žฅ์€ ์‹ค์ œ ๋ฌธ์ œ๋ณด๋‹ค ํ›„ํฌ๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์— ๋Œ€ํ•œ ์ดํ•ด ๋ถ€์กฑ์œผ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
์ด๋Ÿฌํ•œ ์งˆ๋ฌธ์—๋Š” ๋ชจ๋“  ํ›„ํฌ์™€ ์ผ์น˜ํ•˜๋Š” ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜๋œ ๋‹ต๋ณ€์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ปจํŠธ๋กค๋Ÿฌ์˜ ์ˆ˜๋ช…์ฃผ๊ธฐ๊ฐ€ ํ•ด๋‹น ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ๋ฌด์—‡์ธ์ง€ ์ „ํ˜€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

๋˜ํ•œ ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•  ํ•„์š”๋„ ์—†์Šต๋‹ˆ๋‹ค. ๋” ์ด์ƒ ๊ฐœ๋ฐœ์ž์˜ ์ฑ…์ž„์ด ์•„๋‹™๋‹ˆ๋‹ค.

์–ดํœ˜ ๋ฒ”์œ„๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ์ง€์†๋ฉ๋‹ˆ๊นŒ? ๊ตญ๊ฐ€์˜ ์ˆ˜๋ช…

๊ตญ๊ฐ€์˜ ์ˆ˜๋ช…

๋ˆ„๊ฐ€ ๊ทธ๊ฒƒ์„ ์†Œ์œ ํ•ฉ๋‹ˆ๊นŒ?

ํ›„ํฌ๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์†Œ์œ ํ•ฉ๋‹ˆ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์†Œ์œ ํ•˜๋Š” useTextEditingController API์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค.
useFocusNode , useScrollController , useAnimationController , ...

์–ด๋–ค ๋ฉด์—์„œ ์ด๋Ÿฌํ•œ ์งˆ๋ฌธ์€ StreamBuilder ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

  • StreamSubscription์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • ๊ตฌ๋…์€ ๊ตญ๊ฐ€์˜ ํ‰์ƒ ๋™์•ˆ ์ง€์†๋ฉ๋‹ˆ๋‹ค.
  • StreamBuilder๋Š” StreamSubscription์„ ์†Œ์œ ํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ์„ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

final value = useX(argument);

๋‹ค์Œ๊ณผ ์™„์ „ํžˆ ๋™๋“ฑํ•ฉ๋‹ˆ๋‹ค.

XBuilder(
  argument: argument,
  builder: (context, value) {

  },
);

๊ทธ๋“ค์€ ๊ฐ™์€ ๊ทœ์น™๊ณผ ๊ฐ™์€ ํ–‰๋™์„ ํ•ฉ๋‹ˆ๋‹ค.

๋” ์ด์ƒ ๊ฐœ๋ฐœ์ž์˜ ์ฑ…์ž„์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทผ๋ณธ์ ์œผ๋กœ ๊ทธ๊ฒƒ์ด ์—ฌ๊ธฐ์—์„œ ์˜๊ฒฌ ๋ถˆ์ผ์น˜๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ์ •์˜๋œ ์ˆ˜๋ช…์ด ์žˆ๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์™€ ๊ฐ™์€ API๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ IMHO์—์„œ ํ•ด๋‹น ๊ฐ’์„ ํด๋กœ์ €์— ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” API์™€ ๊ทผ๋ณธ์ ์œผ๋กœ ๋งค์šฐ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

์ด ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“œ๋Š” ์‚ฌ๋žŒ์—๊ฒŒ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ํ•ต์‹ฌ flutter API์— ํฌํ•จํ•˜๊ณ  ์‹ถ์€ ์ข…๋ฅ˜์™€ ๋ฐ˜๋Œ€๋˜๋Š” ์Šคํƒ€์ผ์ž…๋‹ˆ๋‹ค.

@Hixie
@rrousselGit ์ด ๋งํ•œ ๊ฒƒ์€ ๊ทธ๋“ค์ด ๊ฐ™์€ ๊ฒƒ์ด์ง€๋งŒ ๋ผ์ดํ”„ ์‚ฌ์ดํด๊ณผ ๊ด€๋ จํ•˜์—ฌ "๋™์ผํ•œ ๊ทœ์น™๊ณผ ๋™์ผํ•œ ํ–‰๋™"์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ณ์€?

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๋“ค์€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์—ฌ๊ธฐ์—์„œ ํ‹€๋ ธ์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ง€๋‚œ ๊ฐ€์„์— flutter๋ฅผ ์‹œ๋„ํ•  ๋•Œ ํ•œ ์œ„์ ฏ์— ์„ธ ๊ฐœ์˜ ๋นŒ๋”๊ฐ€ ํ•„์š”ํ–ˆ๋‹ค๋ฉด ๋งŽ์€ ์ค‘์ฒฉ์ด ๋˜์—ˆ์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ›„ํฌ 3๊ฐœ(์„  3๊ฐœ)์— ๋น„ํ•ด.
๋˜ํ•œ. ํ›„ํฌ๋Š” ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ์—ฌ๋Ÿฌ ํ›„ํฌ๋กœ ๊ตฌ์„ฑ๋œ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค๋ฅธ ํ›„ํฌ์™€ ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€ ๋…ผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ƒˆ ํ›„ํฌ๋ฅผ ๋งŒ๋“ค๊ณ  ํ•˜๋‚˜์˜ ์ƒˆ ํ›„ํฌ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์ ฏ ๊ฐ„์— ์ƒํƒœ ๋กœ์ง์„ ์‰ฝ๊ฒŒ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ฒƒ์€ 2019๋…„ ํ”Œ๋Ÿฌํ„ฐ ๊ฐ€์„์„ ์‹œ๋„ํ•  ๋•Œ ๋‚ด๊ฐ€ ๋†“์นœ ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก  ๋‹ค๋ฅธ ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์ด ๋งŽ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๊ทธ๊ฒƒ์€ ์ด๋ฏธ ํ•ด๊ฒฐ๋˜์—ˆ๊ณ  ๋‚˜๋Š” ๋ฌธ์„œ์—์„œ ๊ทธ๊ฒƒ์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ์ผ๋“ฑ ์‹œ๋ฏผ์œผ๋กœ์„œ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋™์ผํ•œ ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ›„ํฌ ๋˜๋Š” ๋‹ค๋ฅธ ์†”๋ฃจ์…˜๊ณผ ๊ฐ™์€ ๊ฒƒ์ด ๊ฐœ๋ฐœ ์†๋„๋ฅผ ํฌ๊ฒŒ ๋†’์ด๊ธฐ ์œ„ํ•ด ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

OP๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋ชจ๋“  ์ข…๋ฅ˜์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋นŒ๋” ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์€ initState/dispose๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ์™œ ๋ฌธ์ œ์ธ์ง€ ์ž˜ ์ดํ•ด๊ฐ€ ์•ˆ๋ฉ๋‹ˆ๋‹ค.

์‚ฌ๋žŒ๋“ค์ด https://github.com/flutter/flutter/issues/51752#issuecomment -664787791์˜ ์ฝ”๋“œ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ๋Š๋ผ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด initState/dispose๋ณด๋‹ค ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์ด ํ›„ํฌ๋ฅผ ์ข‹์•„ํ•œ๋‹ค๋ฉด ๊ทธ๊ฒƒ๋„ ์ข‹์•„ํ•ฉ๋‹ˆ๊นŒ? ํ›„ํฌ๊ฐ€ ๋” ๋‚˜์€๊ฐ€์š”? ๋” ๋‚˜์œ?

@Hixie Hooks๋Š” ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ๋‹จ์ผ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๊ตฌ๋ถ„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด useAnimationController ์™€ ๊ฐ™์ด initState์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ณ  ๋” ์ด์ƒ ํ๊ธฐํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž์˜ ์ฑ…์ž„์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋งŒ๋“  ๋ชจ๋“  ๋‹จ์ผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ๊ธฐํ–ˆ๋Š”์ง€ ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

initState ๋ฐ dispose ๋Š” ๋‹จ์ผ ํ•ญ๋ชฉ์—๋Š” ์ ํ•ฉํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ ์ด์งˆ ์œ ํ˜•์˜ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ์ƒํ•ด ๋ณด์‹ญ์‹œ์˜ค. ํ›„ํฌ๋Š” ํด๋ž˜์Šค์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ๋ถ„์‚ฐ๋˜๋Š” ๋Œ€์‹  ๋…ผ๋ฆฌ์  ์ถ”์ƒํ™” ๋‹จ์œ„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด ๋ฌป๋Š” ๊ฒƒ์ด ๋งค๋ฒˆ ์ˆ˜๋™์œผ๋กœ ํšจ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์™œ ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š”์ง€ ๋ฌป๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์™„์ „ํžˆ ๊ฐ™์ง€๋Š” ์•Š์ง€๋งŒ ๋Œ€์ฒด๋กœ ๋น„์Šทํ•œ ๋Š๋‚Œ์ด ๋“ ๋‹ค๋Š” ์ ์—๋Š” ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด์ „์— ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋„ˆ๋ฌด ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ flutter_hooks ํŒจํ‚ค์ง€์™€ ํ•จ๊ป˜ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘์†Œ ๊ทœ๋ชจ์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๋Š๋‚Œ์ธ๊ฐ€์š”. ์ €๋Š” Flutter ์‚ฌ์šฉ์ž๋กœ์„œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ›„ํฌ๊ฐ€ ์†”๋ฃจ์…˜์„ ์ œ๊ณตํ•˜๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ์— ๋ถ€๋”ช์ณค์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ์‹ค์ œ๋กœ ์šฐ๋ฆฌ์—๊ฒŒ ์กด์žฌํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ํ™•์‹ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ด ์žˆ์œผ๋ฉด ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

React ๊ด€์ ์—์„œ ๋ช‡ ๊ฐ€์ง€ ์ƒ๊ฐ์„ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ๋“ค์ด ๊ด€๋ จ์ด ์—†๋‹ค๋ฉด ์šฉ์„œํ•˜์ง€๋งŒ Hooks์— ๋Œ€ํ•ด ์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜๋Š”์ง€ ๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ํ™•์‹คํžˆ "์ˆจ๊ธฐ๊ธฐ"์ž…๋‹ˆ๋‹ค. ๋˜๋Š” ์–ด๋–ป๊ฒŒ ๋ณด๋Š๋ƒ์— ๋”ฐ๋ผ ์บก์Šํ™”ํ•˜์‹ญ์‹œ์˜ค. ํŠนํžˆ, ๊ทธ๊ฒƒ๋“ค์€ ์ง€์—ญ ์ƒํƒœ์™€ ํšจ๊ณผ๋ฅผ ์บก์Šํ™”ํ•ฉ๋‹ˆ๋‹ค(์ €๋Š” ์šฐ๋ฆฌ์˜ "ํšจ๊ณผ"๊ฐ€ "์ผํšŒ์šฉ"๊ณผ ๊ฐ™์€ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค). "์•”์‹œ์„ฑ"์€ ํ˜ธ์ถœ๋˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ์— ์ˆ˜๋ช…์„ ์ž๋™์œผ๋กœ ์ฒจ๋ถ€ํ•œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋‚ด์žฌ์„ฑ์€ ๋ชจ๋ธ์— ๋‚ด์žฌ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ธ์ˆ˜๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ์Šค๋ ˆ๋“œ๋˜๋Š” ๊ฒƒ์„ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ ์ž์ฒด์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ Hook, ๊ฐ ๊ธฐ๋ณธ Hook์— ์ด๋ฅด๊ธฐ๊นŒ์ง€ ๋ง์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์ด ์‹œ๋„๋Ÿฝ๊ณ  ์‹ค์ œ๋กœ ์œ ์šฉํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ Component๋ฅผ ์•”์‹œ์  ์ „์—ญ ์ƒํƒœ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ VM์˜ throw errorHandlerFrame ๊ฐ€ ์ฝ”๋“œ์—์„œ catch ๋ธ”๋ก์„ ์œ„์ชฝ์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ข‹์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€์— ์•”์‹œ์  ์€๋‹‰ ์ƒํƒœ๊ฐ€ ์žˆ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ข‹์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๊นŒ? ๊ทธ๋Ÿฌ๋‚˜ React์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ปดํฌ๋„ŒํŠธ์˜ ์š”์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์€ (UI ํŠธ๋ฆฌ์˜ ์œ„์น˜์— ํ•ด๋‹นํ•˜๋Š”) ์ˆ˜๋ช…์ด ์—ฐ๊ฒฐ๋œ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ ์ž์ฒด๊ฐ€ ์ƒํƒœ์™€ ๊ด€๋ จํ•˜์—ฌ ๋ฐœํŒ์ด ์•„๋‹Œ ์ด์œ ๋Š” ์ž„์˜์˜ ์ฝ”๋“œ์—์„œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ UI ์ฝ”๋“œ์˜ ์ปจํ…์ŠคํŠธ์— ๋‚จ์•„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜๋ช…์ด ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ๊ตฌ์„ฑ ์š”์†Œ ํ˜•ํƒœ์ธ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ƒํƒœ+ํšจ๊ณผ์™€ ๋‚˜๋ฌด ์œ„์น˜์— ์—ฐ๊ฒฐ๋œ ์ˆ˜๋ช…์ด๋ผ๋Š” ๋‘ ๊ฐ€์ง€ ๋Šฅ๋ ฅ์„ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์ฒซ ๋ฒˆ์งธ ๋Šฅ๋ ฅ์ด ๊ทธ ์ž์ฒด๋กœ ์œ ์šฉํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ์ฝ”๋“œ๋ฅผ ์บก์Šํ™”ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ ์œ ์šฉํ•˜๋“ฏ์ด ํŠธ๋ฆฌ์— ์ƒˆ ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ์ƒํƒœ+ํšจ๊ณผ ๋ฒˆ๋“ค์„ ์บก์Šํ™”(๋ฐ ์žฌ์‚ฌ์šฉ)ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ณธ ์š”์†Œ๊ฐ€ ๋ถ€์กฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ Hooks์ž…๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ = ํ›„ํฌ + ๋ฐ˜ํ™˜๋œ UI.

๋‚ด๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ปจํ…์ŠคํŠธ ์ƒํƒœ๋ฅผ ์ˆจ๊ธฐ๋Š” ์ž„์˜์˜ ํ•จ์ˆ˜๋Š” ๋ฌด์„ญ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ๋ฆฐํ„ฐ๋ฅผ ํ†ตํ•ด ๊ทœ์น™์„ ์‹œํ–‰ํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. Hook์—๋Š” "์ƒ‰์ƒ" ์ด ์žˆ์Šต๋‹ˆ๋‹ค. Hook์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๋„ Hook์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ฆฐํ„ฐ๋Š” ์ปดํฌ๋„ŒํŠธ๋‚˜ ๋‹ค๋ฅธ Hooks๋งŒ์ด Hooks๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ด์ œ ๊ตฌ์„ฑ ์š”์†Œ ์ž์ฒด๋ณด๋‹ค ๋” ์•”์‹œ์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ปจํ…์ŠคํŠธ UI ์ƒํƒœ๋ฅผ ์ˆจ๊ธฐ๋Š” ์ž„์˜ ํ•จ์ˆ˜์˜ ๋ฌธ์ œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋…์ ์œผ๋กœ ์šฐ๋ฆฌ๋Š” Hook ํ˜ธ์ถœ์„ ์ผ๋ฐ˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๋ณด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. useState() ๋Š” ๊ตฌ๋ฌธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ use State() ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์–ธ์–ด ๊ธฐ๋Šฅ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํšจ๊ณผ ์ถ”์  ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ์–ธ์–ด์—์„œ ๋Œ€์ˆ˜ ํšจ๊ณผ๊ฐ€ ์žˆ๋Š” Hooks์™€ ๊ฐ™์€ ๊ฒƒ์„ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ ๊ทธ๊ฒƒ๋“ค ์€ ์ผ๋ฐ˜ ํ•จ์ˆ˜์ด์ง€๋งŒ State๋ฅผ "์‚ฌ์šฉ"ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์€ ํƒ€์ž… ์„œ๋ช…์˜ ์ผ๋ถ€๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ React ์ž์ฒด๋ฅผ ์ด ํšจ๊ณผ์— ๋Œ€ํ•œ "์ฒ˜๋ฆฌ์ž"๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด์จŒ๋“  ์ด๊ฒƒ์€ ๋งค์šฐ ์ด๋ก ์ ์ด์ง€๋งŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์˜ ๊ด€์ ์—์„œ ์„ ํ–‰ ๊ธฐ์ˆ ์„ ์ง€์ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

์‹ค์šฉ์ ์ธ ์ธก๋ฉด์—์„œ ์—ฌ๊ธฐ์—๋Š” ๋ช‡ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ์งธ, Hooks๊ฐ€ React์˜ "์ถ”๊ฐ€" API๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ์ ์— ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์€์ด ์‹œ์ ์—์„œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ์œ„ํ•œ API ๋ฐ˜์‘์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๋“ค์ด ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์œผ๋กœ์„œ ๊ทธ๋‹ค์ง€ ๋งค๋ ฅ์ ์ด์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ‹€๋ฆผ์—†์ด ๋‹ค๋ฅธ ์ „์ฒด ํŒจ๋Ÿฌ๋‹ค์ž„์„ ๊ฐ€์ง„ Flutter์— ๋Œ€ํ•ด ๊ทธ๋“ค์ด ์ •๋ง๋กœ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ๋“ค์ด ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์— ๊ด€ํ•ด์„œ๋Š”, ํ•ต์‹ฌ ๊ธฐ๋Šฅ์€ ์ƒํƒœ+์œ ํšจ ๋กœ์ง์„ ์บก์Šํ™”ํ•œ ๋‹ค์Œ ์ผ๋ฐ˜ ํ•จ์ˆ˜ ๊ตฌ์„ฑ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋Š” ๊ตฌ์„ฑํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— useState() ์™€ ๊ฐ™์€ ์ผ๋ถ€ ํ›„ํฌ ์ถœ๋ ฅ์„ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉ์ž ์ •์˜ useGesture(state) ์— ๋Œ€ํ•œ ์ž…๋ ฅ์œผ๋กœ ์ „๋‹ฌํ•œ ๋‹ค์Œ ์ด๋ฅผ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž ์ •์˜ useSpring(gesture) ์ž…๋ ฅ์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ์ฐจ ๊ฐ’์„ ์ œ๊ณตํ•˜๋Š” ๋ฐ๋ชจ ์™€ Hooks๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๊ฐ„๋žตํ•˜๊ฒŒ ์š”์•ฝํ•œ ๊ธฐ์‚ฌ ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ์ƒ์šฉ๊ตฌ๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ƒํƒœ ์ €์žฅ ์บก์Šํ™”๋œ ๋กœ์ง์˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋™์ ์œผ๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๋Šฅ๋ ฅ์— ๊ด€ํ•œ

์ด๊ฒƒ์ด ์กฐ๊ธˆ์ด๋ผ๋„ ๋„์›€์ด ๋˜์—ˆ๋Š”์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์— ๋Œ€ํ•œ ๊ด€์ ์„ ์กฐ๊ธˆ์ด๋ผ๋„ ๋ฒ—์–ด๋‚˜๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.
๋‹ค๋ฅธ ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

OP๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋ชจ๋“  ์ข…๋ฅ˜์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋นŒ๋” ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์€ initState/dispose๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ์™œ ๋ฌธ์ œ์ธ์ง€ ์ž˜ ์ดํ•ด๊ฐ€ ์•ˆ๋ฉ๋‹ˆ๋‹ค.

์‚ฌ๋žŒ๋“ค์ด #51752 (comment) ์˜ ์ฝ”๋“œ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ๋Š๋ผ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด initState/dispose๋ณด๋‹ค ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์ด ํ›„ํฌ๋ฅผ ์ข‹์•„ํ•œ๋‹ค๋ฉด ๊ทธ๊ฒƒ๋„ ์ข‹์•„ํ•ฉ๋‹ˆ๊นŒ? ํ›„ํฌ๊ฐ€ ๋” ๋‚˜์€๊ฐ€์š”? ๋” ๋‚˜์œ?

late ํ‚ค์›Œ๋“œ๋Š” ์ƒํ™ฉ์„ ๊ฐœ์„ ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ Property ๋Š” ๋…๋ฆฝ์ ์ด๊ฑฐ๋‚˜ ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ์ƒํƒœ์— ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ ์ƒํ™ฉ์—์„œ๋Š” ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋” ์ •ํ™•ํ•˜๊ฒŒ๋Š” "์—…๋ฐ์ดํŠธ" ๋ถ€๋ถ„์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด StreamBuilder ํ•˜๋ฉด ์ˆ˜์‹ ๋˜๋Š” ์ŠคํŠธ๋ฆผ์ด ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ์ฒด๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ์ดˆ๊ธฐํ™”๋˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์— ๊ทธ๋Ÿฌํ•œ ๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๋Š” ์‰ฌ์šด ์†”๋ฃจ์…˜์ด ์—†์Šต๋‹ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ›„ํฌ์—๋Š” ์œ„์ ฏ์˜ Key ์™€ ๋™์ผํ•œ ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ•ด๋‹น ํ‚ค๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์ƒํƒœ ์กฐ๊ฐ์ด ์†Œ๋ฉธ๋˜๊ณ  ๋‹ค์‹œ ์ƒ์„ฑ๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด useMemo ๋Š” ๊ฐœ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์บ์‹œํ•˜๋Š” ํ›„ํฌ์ž…๋‹ˆ๋‹ค.
ํ‚ค์™€ ๊ฒฐํ•ฉํ•˜์—ฌ useMemo ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•”์‹œ์  ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด ์œ„์ ฏ์€ ๋ฉ”์‹œ์ง€ ID๋ฅผ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ฉ”์‹œ์ง€ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•ด๋‹น ๋ฉ”์‹œ์ง€ ID๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์„ธ๋ถ€์ •๋ณด๋ฅผ ๋‹ค์‹œ ๊ฐ€์ ธ์™€์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

useMemo ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

String messageId;

Widget build(context) {
  final Future<Message> message = useMemo(() => fetchMessage(messageId), [messageId]);

}

์ด ์ƒํƒœ์—์„œ ๋‹ค์‹œ ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ๋ฅผ 10๋ฒˆ ํ˜ธ์ถœํ•ด๋„ messageId ๊ฐ€ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋Š” ๋‹ค์‹œ ์ˆ˜ํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ messageId ๋ณ€๊ฒฝ๋˜๋ฉด ์ƒˆ๋กœ์šด Future ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.


ํ˜„์žฌ ์ƒํƒœ์˜ flutter_hooks ๊ฐ€ Dart์— ๋Œ€ํ•ด ์ •์ œ๋˜์ง€ ์•Š์•˜๋‹ค๋Š” ์ ์€ ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ๊ตฌํ˜„์€ ๋ณธ๊ฒฉ์ ์ธ ์•„ํ‚คํ…์ฒ˜๋ณด๋‹ค POC์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ StatefulWidgets์˜ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์–ด๋”” ์žˆ๋Š”์ง€ ๊ธฐ์–ต๋‚˜์ง€ ์•Š์•˜์ง€๋งŒ ์ด์ƒ์ ์ธ ์„ธ๊ณ„์˜ ํ›„ํฌ๋Š” async* & sync* ์˜†์— ์žˆ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜ ์ƒ์„ฑ๊ธฐ๊ฐ€ ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ œ์•ˆํ•œ ๊ฒƒ์„ ๊ธฐ์–ตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” Dan์ด use State ์ œ์•ˆํ•œ ๊ฒƒ๊ณผ ์œ ์‚ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. useState

@gaearon

์ด๊ฒƒ์€ ์ƒ์šฉ๊ตฌ๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ƒํƒœ ์ €์žฅ ์บก์Šํ™”๋œ ๋…ผ๋ฆฌ์˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋™์ ์œผ๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๋Šฅ๋ ฅ์— ๊ด€ํ•œ ๊ฒƒ์ž„์„ ๊ฐ•์กฐํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋…ผ์˜๋˜๋Š” ๋ฌธ์ œ๋Š” ๊ทธ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์„ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ธฐ ์œ„ํ•ด ๋ณ„๋„์˜ ๋ฒ„๊ทธ๋ฅผ ์ œ์ถœํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. (๊ทธ๊ฒƒ์€ ๋งค์šฐ ๋‹ค๋ฅธ ๋ฌธ์ œ์ฒ˜๋Ÿผ ๋“ค๋ฆฌ๊ณ  ์†”์งํžˆ ์—ฌ๊ธฐ์— ์„ค๋ช…๋œ ๋ฌธ์ œ๋ณด๋‹ค ๋” ์„ค๋“๋ ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.) ์ด ๋ฒ„๊ทธ๋Š” ํŠนํžˆ ์ผ๋ถ€ ๋…ผ๋ฆฌ๊ฐ€ ๋„ˆ๋ฌด ์žฅํ™ฉํ•œ ๋ฐฉ๋ฒ•์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์•„๋‹ˆ์š”, ๊ทธ๊ฐ€ ์˜ณ์•˜์Šต๋‹ˆ๋‹ค. ํ˜ผ๋ž€ ์Šค๋Ÿฌ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด๊ฒƒ์€ ์ฝ”๋“œ ์ค„ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ฝ”๋“œ ์ค„ ์ž์ฒด์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ƒํƒœ๋ฅผ ์ธ์ˆ˜๋ถ„ํ•ดํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๋ฒ„๊ทธ๋Š” "์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๊ณ /์–ด๋ ต์Šต๋‹ˆ๋‹ค"๋ผ๋Š” ๋ฌธ์ œ์™€ initState์—์„œ ์„ ์–ธํ•  ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•œ ์†์„ฑ์ด ์žˆ์„ ๋•Œ ์ƒํƒœ์— ๋„ˆ๋ฌด ๋งŽ์€ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๋Š” ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋งค์šฐ ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค. dispose ๋ฐ debugFillProperties์—์„œ. ๊ด€์‹ฌ ์žˆ๋Š” ๋ฌธ์ œ๊ฐ€ ๋‹ค๋ฅธ ๋ฌธ์ œ์ธ ๊ฒฝ์šฐ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์ƒˆ ๋ฒ„๊ทธ๋ฅผ ์ œ์ถœํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

ํ’€๊ณ ์ž ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ์™„์ „ํžˆ ์ดํ•ดํ•  ๋•Œ๊นŒ์ง€ ํ›„ํฌ(๋˜๋Š” ๋ชจ๋“  ์†”๋ฃจ์…˜)๋ฅผ ์žŠ์–ด๋ฒ„๋ฆฌ๊ธฐ๋ฅผ ์ •๋ง, ์ •๋ง ๊ฐ•๋ ฅํ•˜๊ฒŒ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•ด์•ผ๋งŒ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ์„ค๋“๋ ฅ ์žˆ๋Š” ์ฃผ์žฅ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์ด ํ•ด๊ฒฐํ•˜๋Š” ๋ฌธ์ œ์— ๋Œ€ํ•ด ๊ธฐ๋Šฅ์„ ํ‰๊ฐ€ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด ๊ทธ ๋ฌธ์ œ์—์„œ ๋‚ด๊ฐ€ ๋งํ•œ ๊ฒƒ์„ ์˜คํ•ดํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ์ƒ์šฉ๊ตฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ์„ฑ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ์šฉ๊ตฌ๋Š” ์›์ธ์ด ์•„๋‹ˆ๋ผ ์žฌ์‚ฌ์šฉ์„ฑ ๋ฌธ์ œ์˜ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์—์„œ ์„ค๋ช…ํ•˜๋Š” ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉ/๊ตฌ์„ฑํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์€ ๋ฏน์Šค์ธ, ๋นŒ๋” ๋˜๋Š” ์žฌ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋‘ ๊ณ ์œ ํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด ์˜ต์…˜์˜ ๋ฌธ์ œ๋Š” ์ƒ์šฉ๊ตฌ์™€ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋นŒ๋”์˜ ์ƒ์šฉ๊ตฌ๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์€ ํ•˜๋‚˜์˜ ๊ฒฝ๋กœ(ํ›„ํฌ๊ฐ€ ํ•˜๋Š” ์ผ)์ด์ง€๋งŒ ๋‹ค๋ฅธ ๊ฒฝ๋กœ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ž ์‹œ ๋™์•ˆ ์ œ์•ˆํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

context.onDidChangeDependencies(() {

});
context.onDispose(() {

});

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ๋“ค์€ ๊ทธ๋“ค๋งŒ์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ๊ณ  ๋ฌธ์ œ๋ฅผ ์™„์ „ํžˆ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ €๋Š” ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

@rrousselGit , ๋ฌธ์ œ๋ฅผ ๋” ์ž˜ ๋ฐ˜์˜ํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๊ธฐ ๋งจ ์œ„์— ์žˆ๋Š” ์›๋ž˜ ๋ฌธ์ œ ์„ค๋ช…์„ ์ž์œ ๋กญ๊ฒŒ ํŽธ์ง‘ํ•˜์„ธ์š”. : ๋˜ํ•œ ์„ค๊ณ„ ๋ฌธ์„œ ์ž‘์„ฑ ์ฃผ์‹œ๊ธฐ https://flutter.dev/docs/resources/design-docs ๋ฌธ์ œ ๋ฌธ์˜ ์†Œ๊ฐ ๊ฐ€๋Šฅ ๋ฐ•๋žŒํšŒ์— ์ง€๊ธˆ ์ดˆ์ ์„ @Hixie์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ์šฐ๋ฆฌ๊ฐ€ ๋‹ค์‹œ ํ•จ๊ป˜ (์— ๋ฐ˜๋ณต ํ•  ์ˆ˜ ์žˆ์Œ์„ ). ์ €๋Š” ์—ฌ๋Ÿฌ๋ถ„์ด ๋‹ค๋ฅธ Flutter ์—”์ง€๋‹ˆ์–ด์ฒ˜๋Ÿผ ํž˜์„ ์–ป์—ˆ์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์€ ํŒ€์˜ ์ผ์›์ด๋ฏ€๋กœ ํ•จ๊ป˜ ๋ฐ˜๋ณตํ•ฉ์‹œ๋‹ค!

๋‚˜๋Š” ๊ทธ ๋ฌธ์ œ๋ฅผ ๋ช‡ ๋ฒˆ์ด๊ณ  ๋‹ค์‹œ ์‚ดํŽด๋ณด์•˜๋‹ค. ์†”์งํžˆ ์–ด๋””์„œ๋ถ€ํ„ฐ ์˜คํ•ด๊ฐ€ ์ƒ๊ธฐ๋Š”์ง€ ์ดํ•ด๊ฐ€ ์•ˆ๊ฐ€์„œ ์–ด๋–ป๊ฒŒ ๊ฐœ์„ ํ•ด์•ผ ํ• ์ง€ ๊ฐ์ด ์•ˆ์žกํžˆ๋„ค์š”.
์›๋ž˜ ์ฃผ์„์€ ์žฌ์‚ฌ์šฉ์„ฑ/์ธ์ˆ˜๋ถ„ํ•ด์— ๋Œ€ํ•œ ์š•๊ตฌ๋ฅผ ๋ฐ˜๋ณตํ•ด์„œ ์–ธ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค. ์ƒ์šฉ๊ตฌ์— ๋Œ€ํ•œ ์–ธ๊ธ‰์€ "Flutter๋Š” ์žฅํ™ฉํ•ฉ๋‹ˆ๋‹ค"๊ฐ€ ์•„๋‹ˆ๋ผ "์ผ๋ถ€ ๋…ผ๋ฆฌ๋Š” ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค"์ž…๋‹ˆ๋‹ค.

๋””์ž์ธ ๋ฌธ์„œ ์ œ์•ˆ์ด ๊ณต์ •ํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋ฌธ์„œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ์ƒ๋‹นํ•œ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋ฉฐ, ์ €๋Š” ์—ฌ๊ฐ€ ์‹œ๊ฐ„์— ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ํ›„ํฌ์— ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‚ด ๊ด€์‹ฌ์‚ฌ๋ฅผ ์œ„ํ•ด ์ด ๋ฌธ์ œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ธ์‹์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋ช‡ ์ฃผ ์ „์— ์ €๋Š” ๊ธฐ์กด Flutter ์•ฑ์— ๋Œ€ํ•œ ์•„ํ‚คํ…์ฒ˜์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ์—ฌ๊ธฐ์— ์–ธ๊ธ‰๋œ ๋‚ด์šฉ์ด ์ •ํ™•ํžˆ ์ผ์น˜ํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • ์—ฌ๋Ÿฌ ์œ„์ ฏ์—์„œ ์žฌ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๋…ผ๋ฆฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(๋กœ๋“œ ์ƒํƒœ ์ฒ˜๋ฆฌ/์ผ๋ถ€ ์œ„์ ฏ์ด ํ‘œ์‹œ๋  ๋•Œ "๋ฉ”์‹œ์ง€"๋ฅผ ์ฝ์€ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ/...)
  • ๊ทธ๋“ค์€ ์ฃผ์š” ์•„ํ‚คํ…์ฒ˜ ๊ฒฐํ•จ์„ ์ผ์œผํ‚จ ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋˜ํ•œ ์—ฌ๋Ÿฌ ์œ„์น˜์—์„œ ํ•ด๋‹น ๋…ผ๋ฆฌ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜์—ฌ "์ƒ์„ฑ/์—…๋ฐ์ดํŠธ/์ฒ˜๋ถ„"์„ ์ˆ˜๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
    ์–ด๋–ค ๊ณณ์—์„œ๋Š” ๊ตฌ๋…์„ ๋‹ซ๋Š” ๊ฒƒ์„ ์žŠ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์€ stream ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
  • ์ผ๋ถ€ ์œ„์ ฏ์ด ํ‘œ์‹œ๋  ๋•Œ "๋ฉ”์‹œ์ง€"๋ฅผ ์ฝ์€ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ

๋‚ด ์•ฑ ์ค‘ ํ•˜๋‚˜์—์„œ ๊ฒช์—ˆ๋˜ ๋ฌธ์ œ์™€ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํฅ๋ฏธ๋กœ์šด ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ฑฐ๊ธฐ์—์„œ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์•˜์ง€๋งŒ ์ด ๋ฒ„๊ทธ๊ฐ€ ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์ œ๋Š” ๊ทธ๋‹ค์ง€ ๋งŽ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ๋ฌธ์ œ์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

https://github.com/jocosocial/rainbowmonkey/blob/master/lib/src/views/forums.dart

์‹ค์ œ ๋ฌธ์ œ๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด ์—ฐ๊ตฌํ•  ์ˆ˜ ์žˆ๋Š” ์‹ค์ œ ์•ฑ์˜ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

(BTW, ์ผ๋ฐ˜์ ์œผ๋กœ Streams๋ฅผ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ƒํ™ฉ์„ ์•…ํ™”์‹œํ‚ค๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.)

(BTW, ์ผ๋ฐ˜์ ์œผ๋กœ Streams๋ฅผ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ƒํ™ฉ์„ ์•…ํ™”์‹œํ‚ค๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.)

(์ „์‹ฌ์œผ๋กœ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ปค๋ฎค๋‹ˆํ‹ฐ๋Š” ํ˜„์žฌ ๋ฐ˜๋Œ€ ๋ฐ˜์‘์„ ๋ณด์ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Flutter์—์„œ ๊ณต์‹ ํŒจํ‚ค์ง€๋กœ ChangeNotifier/Listenable/ValueNotifier๋ฅผ ์ถ”์ถœํ•˜๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค)

์‹ค์ œ ๋ฌธ์ œ๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด ์—ฐ๊ตฌํ•  ์ˆ˜ ์žˆ๋Š” ์‹ค์ œ ์•ฑ์˜ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์Šฌํ”„๊ฒŒ๋„ ์•„๋‹ˆ. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์„ ๋„์šฐ๋ฉด์„œ ๊ฒช์€ ๊ฒฝํ—˜์„ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์„ ๋ฟ์ž…๋‹ˆ๋‹ค. ์†์— ๋“  ์•ฑ์ด ์—†์Šต๋‹ˆ๋‹ค.

๋‚ด ์•ฑ ์ค‘ ํ•˜๋‚˜์—์„œ ๊ฒช์—ˆ๋˜ ๋ฌธ์ œ์™€ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํฅ๋ฏธ๋กœ์šด ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ฑฐ๊ธฐ์—์„œ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์•˜์ง€๋งŒ ์ด ๋ฒ„๊ทธ๊ฐ€ ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์ œ๋Š” ๊ทธ๋‹ค์ง€ ๋งŽ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ๋ฌธ์ œ์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„์—์„œ ๋…ผ๋ฆฌ๋Š” ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์—ฐ๊ฒฐ๋˜์ง€ ์•Š๊ณ  _build_ ๋‚ด๋ถ€์— ๋ฐฐ์น˜๋˜๋ฏ€๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
ํŠน์ •ํ•œ ๊ฒฝ์šฐ์— ์˜๋ฏธ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์˜ˆ๊ฐ€ ์ข‹์€ ๊ฒƒ์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋” ๋‚˜์€ ์˜ˆ๋Š” pull-to-refresh์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ pull-to-refresh์—์„œ ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ์„ ์›ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค:

  • ์ฒซ ๋ฒˆ์งธ ๋นŒ๋“œ์—์„œ ๋กœ๋“œ/์˜ค๋ฅ˜ ์ƒํƒœ ์ฒ˜๋ฆฌ
  • ์ƒˆ๋กœ ๊ณ ์นจ ์‹œ:

    • ํ™”๋ฉด์ด ์˜ค๋ฅ˜ ์ƒํƒœ์ธ ๊ฒฝ์šฐ ๋กœ๋”ฉ ํ™”๋ฉด์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

    • ๋กœ๋”ฉ ์ค‘์— ์ƒˆ๋กœ ๊ณ ์นจ์ด ์ˆ˜ํ–‰๋œ ๊ฒฝ์šฐ ๋ณด๋ฅ˜ ์ค‘์ธ HTTP ์š”์ฒญ์„ ์ทจ์†Œํ•ฉ๋‹ˆ๋‹ค.

    • ํ™”๋ฉด์— ์ผ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ํ‘œ์‹œ๋˜๋Š” ๊ฒฝ์šฐ:

    • ์ƒˆ ์ƒํƒœ๊ฐ€ ๋กœ๋“œ๋˜๋Š” ๋™์•ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ„์† ํ‘œ์‹œ

    • ์ƒˆ๋กœ ๊ณ ์นจ์ด ์‹คํŒจํ•˜๋ฉด ์ด์ „์— ์–ป์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ„์† ํ‘œ์‹œํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ์Šค๋‚ต๋ฐ”๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

    • ์ƒˆ๋กœ ๊ณ ์นจ์ด ๋ณด๋ฅ˜ ์ค‘์ธ ๋™์•ˆ ์‚ฌ์šฉ์ž๊ฐ€ ํ™”๋ฉด์„ ํŒ์—…ํ•˜๊ณ  ๋‹ค์‹œ ์ž…๋ ฅํ•˜๋ฉด ๋กœ๋”ฉ ํ™”๋ฉด์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

    • ์ƒˆ๋กœ ๊ณ ์นจ์ด ๋ณด๋ฅ˜ ์ค‘์ธ ๋™์•ˆ RefreshIndicator๊ฐ€ ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” ๋ชจ๋“  ๋ฆฌ์†Œ์Šค์™€ ์—ฌ๋Ÿฌ ํ™”๋ฉด์— ๋Œ€ํ•ด ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ๋ฅผ ์›ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์ผ๋ถ€ ํ™”๋ฉด์—์„œ๋Š” ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒˆ๋กœ ๊ณ ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ChangeNotifier + provider + StatefulWidget์€ ์ด ๋…ผ๋ฆฌ๋ฅผ ์ธ์ˆ˜๋ถ„ํ•ดํ•˜๋Š” ๋ฐ ์ƒ๋‹นํ•œ ์–ด๋ ค์›€์„ ๊ฒช์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด ์ตœ์‹  ์‹คํ—˜(๋ถˆ๋ณ€์„ฑ ๊ธฐ๋ฐ˜ ๋ฐ flutter_hooks ์˜์กด)์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ „์ฒด ์ŠคํŽ™ํŠธ๋Ÿผ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

final productsProvider = FutureProvider<List<Product>>.autoDispose((ref) async {
  final cancelToken = CancelToken();
  ref.onDispose(cancelToken.cancel);

  return await repository.fetchProducts(cancelToken: cancelToken);
});

// ...

Widget build(context) {
  // Listens to the Future created by productsProvider and handles all the refresh logic
  AsyncValue<List<Product>> products = useRefreshProvider(
    productsProvider,
    // TODO consider making a custom hook to encaplusate the snackbar logic
    onErrorAfterRefresh: (err, stack) => Scaffold.of(context).showSnackBar(...),
  );

  return RefreshIndicator(
    onRefresh: () => context.refresh(productsProvider),
    child: products.when(
      loading: () {
        return const SingleChildScrollView(
          physics: AlwaysScrollableScrollPhysics(),
          child: CircularProgressIndicator(),
        );
      },
      error: (err, stack) {
        return SingleChildScrollView(
          physics: const AlwaysScrollableScrollPhysics(),
          child: Text('Oops, something unexpected happened\n$err'),
        );
      },
      data: (products) {
        return ListView.builder(
          itemCount: products.length,
          itemBuilder: (context, index) {
            return ProductItem(products[index]);
          },
        );
      },
    ),
  );
}

์ด ๋…ผ๋ฆฌ๋Š” ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ํ™”๋ฉด ๋‚ด์˜ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค์™€ ํ•จ๊ป˜ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•œ ํ™”๋ฉด์—์„œ ์—ฌ๋Ÿฌ ๋ฆฌ์†Œ์Šค๋ฅผ ํ•œ ๋ฒˆ์— ์ƒˆ๋กœ ๊ณ ์น˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

AsyncValue<First> first = useRefreshProvider(
  firstProvider,
  onErrorAfterRefresh: ...
);
AsyncValue<Second> second = useRefreshProvider(
  secondProvider,
  onErrorAfterRefresh: ...
);

return RefreshIndicator(
  onRefresh: () {
     return Future.wait([context.refesh(firstProvider), context.refresh(secondProvider)]);
  }
  ...
)

์œ„์ ฏ ์™ธ๋ถ€์˜ ์•ฑ ์ƒํƒœ์— ํ•ด๋‹น ๋…ผ๋ฆฌ๋ฅผ ๋ชจ๋‘ ๋„ฃ๊ณ  ์•ฑ ์ƒํƒœ๊ฐ€ ํ˜„์žฌ ์•ฑ ์ƒํƒœ๋ฅผ ๋ฐ˜์˜ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋Œ์–ด์„œ ์ƒˆ๋กœ ๊ณ ์นจ์€ ์œ„์ ฏ ๋‚ด์—์„œ ์ƒํƒœ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ฃผ๋ณ€ ์ƒํƒœ์— ์ƒˆ๋กœ ๊ณ ์นจ์ด ๋ณด๋ฅ˜ ์ค‘์ž„์„ ์•Œ๋ฆฌ๊ณ  ํ–ฅํ›„ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋ฅ˜๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ ์ฃผ๋ณ€ ์ƒํƒœ์˜ ์ฑ…์ž„์ด ์•„๋‹™๋‹ˆ๋‹ค.

์ด ๋กœ์ง์„ ์•ฐ๋น„์–ธํŠธ ์ƒํƒœ๋กœ ๋‘์–ด๋„ UI์—์„œ ๋ชจ๋“  ๋กœ์ง์ด ์ œ๊ฑฐ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.
UI๋Š” ์—ฌ์ „ํžˆ ์˜ค๋ฅ˜๋ฅผ ์ „์ฒด ํ™”๋ฉด์œผ๋กœ ํ‘œ์‹œํ• ์ง€ ์Šค๋‚ต๋ฐ”์— ํ‘œ์‹œํ• ์ง€ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋กœ๋“œํ•  ๋•Œ ์˜ค๋ฅ˜๋ฅผ ๊ฐ•์ œ๋กœ ์ƒˆ๋กœ ๊ณ ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ์žฌ์‚ฌ์šฉ์ด ์ ์Šต๋‹ˆ๋‹ค.
๋ Œ๋”๋ง ๋กœ์ง์ด ์•ฐ๋น„์–ธํŠธ ์ƒํƒœ๊ฐ€ ์•„๋‹Œ ์œ„์ ฏ์— ์™„์ „ํžˆ ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉด _any_ Future์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.Flutter ๋‚ด๋ถ€์— ์ง์ ‘ ํฌํ•จ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด ๋‹น์‹ ์˜ ๋งˆ์ง€๋ง‰ ์˜๊ฒฌ์—์„œ ์˜นํ˜ธํ•˜๋Š” ๊ฒƒ์„ ์ •๋ง๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ์š”์ ์€ ์•ž์„œ ์ธ์šฉํ•œ ์ฝ”๋“œ์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ์œ„์˜ ์ƒˆ๋กœ ๊ณ ์นจ ํ‘œ์‹œ๊ธฐ ์ฝ”๋“œ์ฒ˜๋Ÿผ ๊ฐ„๋‹จํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ƒˆ๋กœ ๊ณ ์นจ ํ‘œ์‹œ๊ธฐ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ์˜ ๊ฒฝ์šฐ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ์ƒํ˜ธ ์ž‘์šฉ์ด ๋งŽ์€ ๊ฒฝ์šฐ ์•ฑ ์ƒํƒœ์— ๋‘๋Š” ๊ฒƒ๋ณด๋‹ค ํ•„์š”ํ•œ ๊ณณ์— ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๊ณณ์— ์บก์Šํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์•ฑ์˜ ์—ฌ๋Ÿฌ ์œ„์น˜์—์„œ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์•ฑ์˜ ๋ชจ๋“  ๋‹จ์ผ ์ƒํ˜ธ ์ž‘์šฉ์— ๋Œ€ํ•œ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ์•Œ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ธฐ๋Šฅ์˜ ๋ณต์žก์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์— ๋™์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌํ•œ ๊ธฐ๋Šฅ์ด ์‰ฝ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์œ„์— ์ œ๊ฐ€ ์ž‘์„ฑํ•œ ํ•œ ์•ฑ์˜ ์†Œ์Šค๋ฅผ ๋งํฌํ–ˆ์Šต๋‹ˆ๋‹ค. ํ™•์‹คํžˆ ์™„๋ฒฝํ•œ ์ฝ”๋“œ๋Š” ์•„๋‹ˆ๋ฉฐ ๋‹ค์Œ ๋ฆด๋ฆฌ์Šค๋ฅผ ์œ„ํ•ด ์ผ๋ถ€๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•  ๊ณ„ํš์ด์ง€๋งŒ ์ด ํ˜ธ์—์„œ ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์ œ๋Š” ๊ฒฝํ—˜ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋‹น์‹ ์€ Flutter์˜ ๊ธฐ์ˆ  ๋ฆฌ๋” ์ค‘ ํ•œ ๋ช…์ž…๋‹ˆ๋‹ค.
๋ฌธ์ œ์— ์ง๋ฉดํ•˜๋”๋ผ๋„ ์ฆ‰์‹œ ํ•ด๊ฒฐ์ฑ…์„ ์ œ์‹œํ•  ์ˆ˜ ์žˆ๋Š” ์ถฉ๋ถ„ํ•œ ๊ธฐ์ˆ ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ ํ•œํŽธ์œผ๋กœ ์ƒ๋‹น์ˆ˜์˜ ์‚ฌ๋žŒ๋“ค์ด ๋‹ค์Œ ์ฝ”๋“œ์˜ ๋ฌธ์ œ์ ์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

FutureBuilder<User>(
  future: fetchUser(),
  builder: ...,
)

์ด ์‚ฌ์‹ค์€ StackOverflow์—์„œ ๋งŒ๋“  Q/AI ๊ฐ€ ์–ผ๋งˆ๋‚˜ ์ธ๊ธฐ๊ฐ€ ์žˆ๋Š”์ง€์— ์˜ํ•ด ์ž…์ฆ๋ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ๋ฐฉ์‹์œผ๋กœ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์ถ”์ƒํ™”ํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค(๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค ์˜๋ฏธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค).
๋ฌธ์ œ๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด ์‹œ๊ฐ„๊ณผ ๊ฒฝํ—˜์ด ๋ชจ๋‘ ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ณต์‹ ์†”๋ฃจ์…˜์„ ์ œ๊ณตํ•จ์œผ๋กœ์จ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ ์ง€ ๊ด€๋ฆฌํ•  ์ˆ˜ ์—†๊ฒŒ ๋  ๊ฐ€๋Šฅ์„ฑ์„ ์ค„์—ฌ ์ „๋ฐ˜์ ์ธ ์ƒ์‚ฐ์„ฑ๊ณผ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.
๋ชจ๋“  ์‚ฌ๋žŒ์ด ๊ท€ํ•˜์˜ ๋ถ€๋™์‚ฐ ์ œ์•ˆ์„ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌํ•œ ๊ฒƒ์ด Flutter ๋‚ด๋ถ€์— ๊ตฌ์ถ•๋œ๋‹ค๋ฉด ๋ฌธ์„œํ™”๋˜๊ณ  ๊ฐ€์‹œ์„ฑ์„ ์–ป์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ถ๊ทน์ ์œผ๋กœ ์ฒ˜์Œ์—๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜์ง€ ๋ชปํ•œ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ์•ฑ์ด ๋ฌด์—‡์ธ์ง€, ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€ ๋“ฑ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์งˆ๋ฌธ์ด "์•ฑ ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๊นŒ?"๋ผ๋ฉด ๋Œ€๋‹ต์€ ํ›„ํฌ์™€ ๊ฐ™์€ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ๊ธฐ์ˆ ์„ ๊ถŒ์žฅํ•˜๋Š” ๋งŽ์€ ๋ฌธ์„œ์ž…๋‹ˆ๋‹ค... ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ์„ธํŠธ์˜ ๋ฌธ์„œ: https://flutter.dev/docs/development/data-and-backend/state-mgmt

์ž„์‹œ ์ƒํƒœ์™€ ์•ฑ ์ƒํƒœ๊ฐ€ ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋„ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‹จ์ผ ์œ ํ˜•์˜ ์œ„์ ฏ์—๋งŒ ๊ด€๋ จ๋˜์ง€๋งŒ ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ํ•ด๋‹น ์œ ํ˜•์˜ ์œ„์ ฏ ๊ฐ„์— ๊ณต์œ ํ•˜๋ ค๋Š” ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ScrollController ๋Š” ์ผ๋ถ€ ์œ ํ˜•์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ชจ๋“  ์•ฑ์—์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ „์—ญ ์•ฑ ์ƒํƒœ์— ๋„ฃ๋Š” ๊ฒƒ์ด ๋ฐ˜๋“œ์‹œ ์ ์ ˆํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๋Ÿฌ ScrollController ๊ฐ€ ๋™์ผํ•œ ๋…ผ๋ฆฌ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฐ๊ฐ์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด ๋…ผ๋ฆฌ๋ฅผ ๊ณต์œ ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ƒํƒœ๋Š” ์—ฌ์ „ํžˆ ScrollController ์ „์šฉ์ด๋ฏ€๋กœ ์ „์—ญ ์•ฑ ์ƒํƒœ๋Š” ์•„๋‹ˆ์ง€๋งŒ ๋…ผ๋ฆฌ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์ด ๋กœ์ง์„ ํŒจํ‚ค์ง•ํ•˜์—ฌ ํ–ฅํ›„ ํ”„๋กœ์ ํŠธ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์—์„œ๋„ ๋” ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. useHooks ์‚ฌ์ดํŠธ๋ฅผ ๋ณด๋ฉด ํŠน์ • ์ผ๋ฐ˜์ ์ธ ์ž‘์—…์„ ๊ตฌ๋ถ„ํ•˜๋Š” ๋งŽ์€ ๋…ผ๋ฆฌ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. useAuth ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ•œ ๋ฒˆ ์ž‘์„ฑํ•˜๊ณ  initState ๋˜๋Š” dispose ํ˜ธ์ถœ์„ ๋†“์ณค๋Š”์ง€ ๋˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜์— then ๊ฐ€ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. catch . ํ•จ์ˆ˜๋Š” ํ•œ ๋ฒˆ๋งŒ ์ž‘์„ฑ๋˜๋ฏ€๋กœ ๊ธฐ๋ณธ์ ์œผ๋กœ ์˜ค๋ฅ˜์˜ ์—ฌ์ง€๊ฐ€ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ์†”๋ฃจ์…˜์€ ๋™์ผํ•œ ์•ฑ์˜ ์—ฌ๋Ÿฌ ๋ถ€๋ถ„๊ณผ ์—ฌ๋Ÿฌ ์•ฑ ๊ฐ„์— ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ตœ์ข… ํ”„๋กœ๊ทธ๋ž˜๋จธ์—๊ฒŒ๋„ ๋” ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๋ฐ˜๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋งํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ, ๊ทธ๊ฒƒ์„ ๋ง‰๋Š” ๊ฒƒ์€ ์•„๋ฌด๊ฒƒ๋„ ์—†์Šต๋‹ˆ๋‹ค. (๋งŒ์•ฝ ๊ทธ๊ฒƒ์„ ๋ฐฉํ•ดํ•˜๋Š” _is_ ๊ฒฝ์šฐ, ๊ทธ๊ฒƒ์— ๋Œ€ํ•œ ๋ฒ„๊ทธ๋ฅผ ์‹ ๊ณ ํ•˜์‹ญ์‹œ์˜ค.)

์ด ๋ฒ„๊ทธ๋Š” ํ›„ํฌ์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ "์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๊ณ /์–ด๋ ต์Šต๋‹ˆ๋‹ค"์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ €๋Š” ์ด๊ฒƒ์ด ์™œ Flutter๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ๊ตฐ๋ถ„ํˆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์–ด๋–ค ์‹์œผ๋กœ๋“  ๊ตฌ์กฐํ™”ํ•˜์—ฌ ์žฅํ™ฉํ•จ์„ ํ”ผํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” ๋งŽ์€ ์˜ˆ์ œ(ํ›… ํฌํ•จ)๊ฐ€ ์žˆ์—ˆ๊ณ  ์ด๋ฏธ ์ด์— ๋Œ€ํ•œ ๋งŽ์€ ๋ฌธ์„œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ Flutter๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๋นŒ๋“œ๋œ ํ›„ํฌ ํŒจํ‚ค์ง€์™€ ๊ฐ™์€ ๊ฒƒ์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ํ›„ํฌ์— ๋Œ€ํ•œ ์ž์‚ฌ ์†”๋ฃจ์…˜์ด ํ•„์š”ํ•œ ์ด์œ ๊ฐ€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? @rrousselGit ์ด ์ด์— ๋Œ€ํ•ด ๋” ์ž˜ ๋‹ต๋ณ€ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๋‹ต๋ณ€์—๋Š” ๋” ๋‚˜์€ ์ง€์›, ๋” ํ†ตํ•ฉ๋œ ์ง€์› ๋ฐ ๋” ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

๊ทธ ์™ธ์—๋„ ํ‘œ๋ฉด์ ์œผ๋กœ flutter_hooks ํŒจํ‚ค์ง€๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ›„ํฌ๋ฅผ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด Flutter๋ฅผ ๊ทผ๋ณธ์ ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ํ˜ผ๋ž€์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

Flutter๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ์ „ํžˆ ๊ณ ์‹ฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์€ ๋‚ด๊ฐ€ Freezed ๋ฅผ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์— Dart์— ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค + ๊ณต์šฉ์ฒด ์œ ํ˜•์ด ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ๊ณผ
Freezed๋Š” ์ด ๋‘ ๊ฐ€์ง€ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์œผ๋กœ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์ƒ๋‹นํžˆ ์ข‹์•„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ๋” ์ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Flutter ํŒ€์€ ์ปค๋ฎค๋‹ˆํ‹ฐ๋ณด๋‹ค ํ›จ์”ฌ ๋” ๋งŽ์€ ์˜ํ–ฅ๋ ฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ „์ฒด ์Šคํƒ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ๋ชจ๋‘ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ๋ถ€๋ถ„์˜ ์ „๋ฌธ๊ฐ€์ธ ์‚ฌ๋žŒ๋“ค; ๊ทธ๋ฆฌ๊ณ  ํ•„์š”ํ•œ ์ผ์„ ํ›„์›ํ•˜๊ธฐ ์œ„ํ•œ ๊ธ‰์—ฌ.

์ด ๋ฌธ์ œ๋Š” ๊ทธ๊ฒƒ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
๊ธฐ์–ตํ•˜์‹ญ์‹œ์˜ค: React ํŒ€์˜ ๋ชฉํ‘œ ์ค‘ ํ•˜๋‚˜๋Š” JSX์™€ ๊ฐ™์ด ํ›„ํฌ๊ฐ€ ์–ธ์–ด์˜ ์ผ๋ถ€๊ฐ€ ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์–ธ์–ด ์ง€์›์ด ์—†๋”๋ผ๋„ ์—ฌ์ „ํžˆ ๋ถ„์„๊ธฐ ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‹คํŠธ ํŒจ๋“œ; ํ”Œ๋Ÿฌํ„ฐ/๊ฐœ๋ฐœ๋„๊ตฌ; Flutter๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ชจ๋“  ๋‹ค์–‘ํ•œ ์ž‘์—…(์˜ˆ: ์•”์‹œ์  ์• ๋‹ˆ๋ฉ”์ด์…˜, ์–‘์‹ ๋“ฑ)์„ ๋‹จ์ˆœํ™”ํ•˜๋Š” ๋งŽ์€ ํ›„ํฌ.

๋น„๋ก Flutter์˜ ์ผ๋ฐ˜์ ์ธ ์ฒ ํ•™์ด ์ž‘์€ ํ•ต์‹ฌ์„ ๊ฐ–๊ณ  ์žˆ๊ธฐ๋Š” ํ•˜์ง€๋งŒ ์ข‹์€ ์ฃผ์žฅ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ Google, cf ์บ๋ฆญํ„ฐ ๋ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ด ์ œ๊ณต๋˜๋Š” ๊ฒฝ์šฐ์—๋„ ํŒจํ‚ค์ง€๋กœ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ ์  ๋” ์ถ”๊ฐ€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ฐฐ์šฐ๊ณ  ๋ณ€ํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋” ํฐ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํŒจํ‚ค์ง€๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ๊ฐ•๋ ฅํ•œ ๊ธฐ์ˆ ์  ์ด์œ ๊ฐ€ ์—†๋Š” ํ•œ(ํ™•์žฅ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ทธ ์–ด๋Š ๋•Œ๋ณด๋‹ค ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ์Œ) ์ด ๊ณต๊ฐ„์— ๋Œ€ํ•ด์„œ๋„ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Flutter์˜ ํ•ต์‹ฌ์— ๋ฌด์–ธ๊ฐ€๋ฅผ ๋„ฃ๋Š” ๊ฒƒ์€ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ๋Š” ์ง์ ‘ ๊ฒฝํ—˜์„ ํ†ตํ•ด ์ž˜ ์•Œ๋‹ค์‹œํ”ผ ์ƒํƒœ๊ฐ€ ๋ฐ˜์‘ํ˜• UI ์•„ํ‚คํ…์ฒ˜์—์„œ ์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋” ๋งŽ์ด ๋ฐฐ์šฐ๋ฉด์„œ ์ง„ํ™”ํ•˜๋Š” ์˜์—ญ์ด๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. 2๋…„ ์ „๋งŒ ํ•ด๋„ ์Šน์ž๋ฅผ ์„ ํƒํ•ด์•ผ ํ–ˆ๋‹ค๋ฉด BLoC๋ฅผ ์„ ํƒํ–ˆ์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๋‹น์—ฐํžˆ ๊ณต๊ธ‰์ž ํŒจํ‚ค์ง€๊ฐ€ ์ธ์ˆ˜๋˜์–ด ํ˜„์žฌ ๊ธฐ๋ณธ ๊ถŒ์žฅ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

flutter_hooks ๋˜๋Š” ๊ฒฌ์ธ๋ ฅ์ด ์žˆ๋Š” ์œ ์‚ฌํ•œ ํ›„ํฌ ํŒจํ‚ค์ง€๋ฅผ ์ง€์›ํ•˜๋Š” Google ๊ณ ์šฉ ๊ธฐ์—ฌ์ž๋ฅผ ํŽธ์•ˆํ•˜๊ฒŒ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋ฌผ๋ก  ์šฐ๋ฆฌ ์˜ ๊ด€์‹ฌ์„ ๋Œ๊ธฐ ์œ„ํ•ด ๊ฒฝ์Ÿํ•˜๋Š” ๋‹ค๋ฅธ ์ž‘์—… ์ด

ํฅ๋ฏธ๋กœ์šด ์ฃผ์žฅ, @timsneath. Rust ์ปค๋ฎค๋‹ˆํ‹ฐ๋„ ๋น„์Šทํ•œ ์ผ์„ ํ•ฉ๋‹ˆ๋‹ค. ์–ธ์–ด๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํ•ต์‹ฌ ๋˜๋Š” ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํ•œ ๋ฒˆ ๋„์ž…๋˜๋ฉด ๊บผ๋‚ด๊ธฐ๊ฐ€ ๋งค์šฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. Rust์˜ ๊ฒฝ์šฐ ์˜์›ํžˆ ์ด์ „ ๋ฒ„์ „๊ณผ์˜ ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ๋ฅผ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ทธ๋“ค์€ ํŒจํ‚ค์ง€๊ฐ€ ๋„์ฐฉํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ์†Œ์ˆ˜์˜ ์Šน์ž๊ฐ€ ๋‚˜ํƒ€๋‚  ๋•Œ๊นŒ์ง€ ์„œ๋กœ ๊ฒฝ์Ÿํ•œ ๋‹ค์Œ ์ด๋ฅผ ์–ธ์–ด๋กœ ์ ‘์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ Flutter์™€ ๋น„์Šทํ•œ ๊ฒฝ์šฐ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. React๊ฐ€ ํด๋ž˜์Šค์—์„œ ํ›„ํฌ๋กœ ์ด๋™ํ•ด์•ผ ํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ํด๋ž˜์Šค๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๊ณ  ์‚ฌ๋žŒ๋“ค์ด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋‚˜์ค‘์— ํ›„ํฌ๋ณด๋‹ค ๋” ๋‚˜์€ ๊ฒƒ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ฝ”์–ด์— ์ถ”๊ฐ€๋˜๊ธฐ ์ „์— ๊ฒฝ์Ÿ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋งˆ๋„ ์šฐ๋ฆฌ ์ปค๋ฎค๋‹ˆํ‹ฐ๋Š” ํ›„ํฌ ์œ„์—์„œ ํ˜์‹ ํ•˜๊ฑฐ๋‚˜ ๋” ๋‚˜์€ ์†”๋ฃจ์…˜์„ ์ฐพ์•„์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ ์šฐ๋ ค๋ฅผ ์ดํ•ดํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์€ Inheritedwidget ๋ฐ StatefulWidget์— ๋” ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์–ธ์–ด ๊ธฐ๋Šฅ๋งŒํผ ๋‚ฎ์„ ์ˆ˜ ์žˆ๋Š” ๋‚ฎ์€ ์ˆ˜์ค€์˜ ๊ธฐ๋ณธ ์š”์†Œ์ž…๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๋…๋ฆฝ์ ์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋Š” ์šด์— ์˜ํ•ด์„œ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
์ด์ „์— ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด ๋ฌธ์ œ์˜ ๋˜ ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

context.onDispose(() {

});

๊ทธ๋ฆฌ๊ณ  ์œ ์‚ฌํ•œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ.
ํ•˜์ง€๋งŒ ํ”„๋ ˆ์ž„์›Œํฌ ๋ฐ–์—์„œ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ค ํŒ€์ด ๋‚˜์˜ฌ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ๊ทธ๋Ÿฌํ•œ ์†”๋ฃจ์…˜์ด Element ๋ฐ”๋กœ ์˜†์— ์žˆ์–ด์•ผ ํ•  ๊ฐ€๋Šฅ์„ฑ์„ ๋ฐฐ์ œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์ด ๋„์›€์ด ๋ฉ๋‹ˆ๊นŒ?

(ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ๋ฌธ์ œ์—์„œ ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚ฌ์Šต๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด ๋ณด๊ณ  ์žˆ๋Š” ๋ฌธ์ œ๋‹น ํ•˜๋‚˜์˜ ๋ฌธ์ œ๋ฅผ ๊ฐ–๊ณ  ์˜ฌ๋ฐ”๋ฅธ ์žฅ์†Œ์—์„œ ์†”๋ฃจ์…˜์„ ๋…ผ์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ •๋ง ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. context.onDispose ๊ฐ€ ์ž์„ธํ•œ ์ •๋ณด ํ‘œ์‹œ์— ์–ด๋–ป๊ฒŒ ๋„์›€์ด ๋˜๋Š”์ง€ ๋ช…ํ™•ํžˆ ํ•ฉ๋‹ˆ๋‹ค.)

๋‚˜๋Š” ์ด๊ฒƒ๊ณผ ๊ด€๋ จํ•˜์—ฌ ์šฐ๋ฆฌ๊ฐ€ ์ƒ๊ฐํ•ด๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ •๋ง ์ข‹์€ ์–ธ์–ด ์ œ์•ˆ์ด ์žˆ๋‹ค๊ณ  ๊ฐ•๋ ฅํžˆ ์˜์‹ฌํ•ฉ๋‹ˆ๋‹ค.

ํŠน์ • ์ƒํƒœ ๊ด€๋ฆฌ ๊ด€์šฉ๊ตฌ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•๋ณด๋‹ค ์ด์— ๋Œ€ํ•ด ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ์ด์•ผ๊ธฐํ•˜๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์šฐ๋ฆฌ๋Š” ๊ทธ๋“ค์ด ๋ฌด์—‡์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ณ  ์–ด๋–ค ์ ˆ์ถฉ์„ ์ˆ˜๋ฐ˜ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋” ์ง„์ง€ํ•˜๊ฒŒ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ VM ๋ฐ JS ๋Ÿฐํƒ€์ž„ ๋ชจ๋‘์—์„œ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์™€ ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

context.onDispose ๊ฐ€ ์žฅํ™ฉํ•จ์— ์–ด๋–ป๊ฒŒ ๋„์›€์ด ๋˜๋Š”์ง€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)

์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด ๋ฌธ์ œ๋Š” ์žฅํ™ฉํ•จ๋ณด๋‹ค ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋” ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์•”์‹œ์ ์œผ๋กœ ์žฅํ™ฉํ•จ์„ ์ค„์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

context.onDispose ๊ฐ€ ์ด ๋ฌธ์ œ์™€ ๊ด€๋ จ๋œ ๋ฐฉ์‹์€ ํ˜„์žฌ ๊ตฌ๋ฌธ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

AnimationController controller;

<strong i="11">@override</strong>
void initState() {
  controller = AnimationController(...);
}

<strong i="12">@override</strong>
void dispose() {
  controller.dispose();
}

๋ฌธ์ œ๋Š”:

  • ์ด๊ฒƒ์€ ํด๋ž˜์Šค ์ •์˜์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ์œ„์ ฏ์ด ์ปค์งˆ์ˆ˜๋ก ์ค‘๊ฐ„์— ์ˆ˜๋ฐฑ ์ค„์˜ ์ฝ”๋“œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธฐํ™”์™€ ์‚ญ์ œ ์‚ฌ์ด์˜ ๊ด€๊ณ„๋ฅผ ์ฝ๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค.

context.onDispose ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<strong i="21">@override</strong>
void initState() {
  controller = AnimationController(...);
  context.onDispose(controller.dispose);
}

ํฅ๋ฏธ๋กœ์šด ๋ถ€๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์ด๊ฒƒ์€ ๋” ์ด์ƒ ํด๋ž˜์Šค ์ •์˜์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ ํ•จ์ˆ˜๋กœ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    ์ด๋ก ์ ์œผ๋กœ ๋ฐ˜๋ณต์žกํ•œ ๋…ผ๋ฆฌ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    ```๋‹คํŠธ
    AnimationController someReusableLogic(BuildContext ์ปจํ…์ŠคํŠธ) {
    ์ตœ์ข… ์ปจํŠธ๋กค๋Ÿฌ = AnimationController(...);
    controller.onDispose(controller.dispose);
    controller.forward();
    ๋ฌดํšจ ๋ฆฌ์Šค๋„ˆ() {}
    controller.addListener(์ฒญ์ทจ์ž);
    context.onDispose(() => controller.removeListener(๋ฆฌ์Šค๋„ˆ));
    }
    ...

@์šฐ์„ธํ•˜๋‹ค
๋ฌดํšจ initState() {
์ปจํŠธ๋กค๋Ÿฌ = someReusableLogic(์ปจํ…์ŠคํŠธ);
}
```

  • ๋ชจ๋“  ๋…ผ๋ฆฌ๊ฐ€ ํ•จ๊ป˜ ๋ฒˆ๋“ค๋ฉ๋‹ˆ๋‹ค. ์œ„์ ฏ์ด 300์œผ๋กœ ๋Š˜์–ด๋‚˜๋”๋ผ๋„ controller ์˜ ๋…ผ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ ์‰ฝ๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • context.myLifecycle(() {...}) ์€(๋Š”) ํ•ซ ๋ฆฌ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ํ•จ์ˆ˜๋ฅผ ์œ„์ ฏ ์ •์˜์— ๋‹จ๋‹จํžˆ ์—ฐ๊ฒฐํ•˜์ง€ ์•Š๊ณ  someReusableLogic ๊ฐ€ StatefulWidget ์—์„œ ์†์„ฑ์„ ์ฝ๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ถˆ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.
    ์˜ˆ๋ฅผ ๋“ค์–ด AnimationController ์˜ Duration ๋Š” ์œ„์ ฏ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ง€์† ์‹œ๊ฐ„์ด ๋ณ€๊ฒฝ๋˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ValueNotifier ์— ์˜์กดํ•˜๊ณ  ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋‹ค๋ฃฐ ํ•„์š” ์—†์ด ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋ถˆ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

    • ์ด๊ฒƒ์€ ๊ณ„์‚ฐ๋œ ์ƒํƒœ์— ํŠนํžˆ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.


์–ธ์–ด ์ œ์•ˆ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์ง€๋งŒ ์ง€๊ธˆ ๋‹น์žฅ์€ ์ด์•ผ๊ธฐํ•  ๊ฐ€์น˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด ๋ฌธ์ œ๋Š” ์žฅํ™ฉํ•จ๋ณด๋‹ค ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ™•์ธ. ์ƒˆ ๋ฒ„๊ทธ๋ฅผ ์‹ ๊ณ ํ•œ ๋‹ค์Œ ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค๋ช…ํ•˜๋Š” ๋ฒ„๊ทธ๋ฅผ ์ œ์ถœํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์ด ๋ฒ„๊ทธ๋Š” ๋ง ๊ทธ๋Œ€๋กœ "์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๊ณ /์–ด๋ ต์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ _this_๋Š” ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

context.onDispose ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<strong i="11">@override</strong>
void initState() {
  controller = AnimationController(...);
  context.onDispose(controller.dispose);
}

์™œ context ๊ฐ€ ์ด๊ฒƒ๊ณผ ๊ด€๋ จ์ด ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค( onDispose ๋Š” ์šฐ๋ฆฌ์˜ ๋ช…๋ช… ๊ทœ์น™์„ ์œ„๋ฐ˜ํ•ฉ๋‹ˆ๋‹ค). ๊ทธ๋Ÿฌ๋‚˜ ํ๊ธฐ ์ค‘์— ์‹คํ–‰ํ•  ํ•ญ๋ชฉ์„ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์›ํ•˜๋ฉด ์˜ค๋Š˜ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

mixin StateHelper<T extends StatefulWidget> on State<T> {
  List<VoidCallback> _disposeQueue;

  void queueDispose(VoidCallback callback) {
    _disposeQueue ??= <VoidCallback>[];
    _disposeQueue.add(callback);
  }

  <strong i="17">@override</strong>
  void dispose() {
    if (_disposeQueue != null) {
      for (VoidCallback callback in _disposeQueue)
        callback();
    }
    super.dispose();
  }
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ˜ธ์ถœํ•˜์‹ญ์‹œ์˜ค.

class _MyHomePageState extends State<MyHomePage> with StateHelper<MyHomePage> {
  TextEditingController controller;

  <strong i="21">@override</strong>
  void initState() {
    super.initState();
    controller = TextEditingController(text: 'button');
    queueDispose(controller.dispose);
  }

  ...
AnimationController someReusableLogic(BuildContext context) {
  final controller = AnimationController(...);
  controller.onDispose(controller.dispose);
  controller.forward();
  void listener() {}
  controller.addListener(listener);
  context.onDispose(() => controller.removeListener(listener));
}
...

<strong i="25">@override</strong>
void initState() {
  controller = someReusableLogic(context);
}

๋‹น์‹ ๋„ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

AnimationController someReusableLogic<T extends StatefulWidget>(StateHelper<T> state) {
  final controller = AnimationController(...);
  state.queueDispose(controller.dispose);
  controller.forward();
  void listener() {}
  controller.addListener(listener);
  state.queueDispose(() => controller.removeListener(listener));
  return controller;
}
...

<strong i="6">@override</strong>
void initState() {
  controller = someReusableLogic(this);
}

์ด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • context.myLifecycle(() {...}) ์€(๋Š”) ํ•ซ ๋ฆฌ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด ์ปจํ…์ŠคํŠธ์—์„œ๋Š” initState์—์„œ ํ˜ธ์ถœ๋œ ํ•ญ๋ชฉ์—๋งŒ ํ•ด๋‹น๋˜๋ฏ€๋กœ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

  • ํ•จ์ˆ˜๋ฅผ ์œ„์ ฏ ์ •์˜์— ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•˜์ง€ ์•Š๊ณ  someReusableLogic ๊ฐ€ StatefulWidget ์—์„œ ์†์„ฑ์„ ์ฝ๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ถˆ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.
    ์˜ˆ๋ฅผ ๋“ค์–ด AnimationController ์˜ Duration ๋Š” ์œ„์ ฏ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ง€์† ์‹œ๊ฐ„์ด ๋ณ€๊ฒฝ๋˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

dispose ํ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ didChangeWidget ํ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

mixin StateHelper<T extends StatefulWidget> on State<T> {
  List<VoidCallback> _disposeQueue;
  List<VoidCallback> _didUpdateWidgetQueue;

  void queueDispose(VoidCallback callback) {
    _disposeQueue ??= <VoidCallback>[];
    _disposeQueue.add(callback);
  }

  void queueDidUpdateWidget(VoidCallback callback) {
    _didUpdateWidgetQueue ??= <VoidCallback>[];
    _didUpdateWidgetQueue.add(callback);
  }

  <strong i="24">@override</strong>
  void didUpdateWidget(T oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (_didUpdateWidgetQueue != null) {
      for (VoidCallback callback in _didUpdateWidgetQueue)
        callback();
    }
  }

  <strong i="25">@override</strong>
  void dispose() {
    if (_disposeQueue != null) {
      for (VoidCallback callback in _disposeQueue)
        callback();
    }
    super.dispose();
  }
}

AnimationController conditionalAnimator(StateHelper state, ValueGetter<bool> isAnimating, VoidCallback listener) {
  final controller = AnimationController(vsync: state as TickerProvider, duration: const Duration(seconds: 1));
  state.queueDispose(controller.dispose);
  controller.addListener(listener);
  state.queueDispose(() => controller.removeListener(listener));
  if (isAnimating())
    controller.repeat();
  state.queueDidUpdateWidget(() {
    if (isAnimating()) {
      controller.repeat();
    } else {
      controller.stop();
    }
  });
  return controller;
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  <strong i="6">@override</strong>
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(animating: false),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.animating}) : super(key: key);

  final bool animating;

  <strong i="7">@override</strong>
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with StateHelper<MyHomePage>, SingleTickerProviderStateMixin {
  AnimationController controller;

  <strong i="8">@override</strong>
  void initState() {
    super.initState();
    controller = conditionalAnimator(this, () => widget.animating, () { print(controller.value); });
  }

  <strong i="9">@override</strong>
  Widget build(BuildContext context) {
    return Center(
      child: FadeTransition(
        opacity: controller,
        child: Text('Hello', style: TextStyle(fontSize: 100.0, color: Colors.white)),
      ),
    );
  }
}
  • ValueNotifier ์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ณ ๋„ ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋ถˆ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

    • ์ด๊ฒƒ์€ ๊ณ„์‚ฐ๋œ ์ƒํƒœ์— ํŠนํžˆ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์—ฌ๊ธฐ์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๊ฐ€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ValueNotifier์™€ ValueListenableBuilder์— ๋ฌด์—‡์ด ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ?

์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด ๋ฌธ์ œ๋Š” ์žฅํ™ฉํ•จ๋ณด๋‹ค ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ™•์ธ. ์ƒˆ ๋ฒ„๊ทธ๋ฅผ ์‹ ๊ณ ํ•œ ๋‹ค์Œ ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค๋ช…ํ•˜๋Š” ๋ฒ„๊ทธ๋ฅผ ์ œ์ถœํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์ด ๋ฒ„๊ทธ๋Š” ๋ง ๊ทธ๋Œ€๋กœ "์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๊ณ /์–ด๋ ต์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์ •๋ณด๊ฐ€ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์ด๊ฒƒ์€ ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

์ €๋Š” ์ด ํ† ๋ก ์ด ์ƒ๋‹นํžˆ ๋ถˆํŽธํ•ด์ง€๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๋ฏธ ์ด ์ ์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋Œ€๋‹ตํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด ๋ฌธ์ œ์˜ ์ฃผ์ œ๋Š” ์žฌ์‚ฌ์šฉ์„ฑ์ด๋ฉฐ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์žฌ์‚ฌ์šฉ์„ฑ ๋ฌธ์ œ์˜ ๊ฒฐ๊ณผ๋กœ ๋…ผ์˜๋ฉ๋‹ˆ๋‹ค. ์ฃผ์š” ์ฃผ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์„ ์–ธ๊ธ‰ํ•˜๋Š” ๋งจ ์œ„ ๋Œ“๊ธ€์—๋Š” ๋‹จ ํ•˜๋‚˜์˜ ๊ธ€๋จธ๋ฆฌ ๊ธฐํ˜ธ๋งŒ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์ฃผ๋กœ 2๊ฐ€์ง€ ์ˆ˜์ค€์˜ ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” StreamBuilder์ž…๋‹ˆ๋‹ค.

์ปจํ…์ŠคํŠธ๊ฐ€ ์ด [...]์™€ ๊ด€๋ จ์ด ์žˆ๋Š” ์ด์œ ๋ฅผ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ๊ธฐ ์ค‘์— ์‹คํ–‰ํ•  ํ•ญ๋ชฉ์„ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์›ํ•˜๋ฉด ์˜ค๋Š˜ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

context.onDispose ์ œ๊ธฐํ–ˆ์„ ๋•Œ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๋ช…์‹œ์ ์œผ๋กœ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค.
ํ† ๋ก ๊ณผ ์–ด๋–ค ๊ด€๋ จ์ด ์žˆ๋Š”์ง€ ๋ฌผ์–ด๋ณด์…จ๊ธฐ ๋•Œ๋ฌธ์— ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.

context ๋Œ€์‹  StateHelper ์ธ ์ด์œ ๋Š” ์ด๊ฒƒ์ด ๋” ์œ ์—ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค(StatelessWidget ์ž‘์—…๊ณผ ๊ฐ™์ด)

context.myLifecycle(() {...})์€ ํ•ซ ๋ฆฌ๋กœ๋“œ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ด ์ปจํ…์ŠคํŠธ์—์„œ๋Š” initState์—์„œ ํ˜ธ์ถœ๋œ ํ•ญ๋ชฉ์—๋งŒ ํ•ด๋‹น๋˜๋ฏ€๋กœ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์šฐ๋ฆฌ๋Š” ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

initState() {
  context.myLifecycle(() => print('hello'));
}

์•ˆ์œผ๋กœ:

initState() {
  context.myLifecycle(() => print('world'));
}

myLifecycle ์ฝœ๋ฐฑ์—๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ:

myLifecycle() {
  super.myLifecycle();
  print('hello');
}

๊ทธ๋Ÿฌ๋ฉด ํ•ซ ๋ฆฌ๋กœ๋“œ๊ฐ€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์—ฌ๊ธฐ์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๊ฐ€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ValueNotifier์™€ ValueListenableBuilder์— ๋ฌด์—‡์ด ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ?

์ด ๊ตฌ๋ฌธ์€ Builders๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์œผ๋ฏ€๋กœ ์›๋ž˜ ๋ฌธ์ œ๋กœ ๋‹ค์‹œ ๋Œ์•„๊ฐ”์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ValueGetter + queueDidUpdateWidget ์ œ์•ˆ ๋Œ€์‹  ํ•จ์ˆ˜๋ฅผ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด ํ•จ์ˆ˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ValueNotifier ๋ฅผ ์ทจํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

AnimationController conditionalAnimator(StateHelper state, ValueListenable<bool> isAnimating, VoidCallback listener) {
...
}

์–ด๋–ค ์œ„์ ฏ์ด ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š”์ง€์— ๋”ฐ๋ผ didUpdateWidget ์•„๋‹Œ ๋‹ค๋ฅธ ๊ณณ์—์„œ isAnimating ๋ฅผ ์–ป๊ณ  ์‹ถ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•œ ๊ณณ์—์„œ๋Š” didUpdateWidget์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฒฝ์šฐ์—๋Š” didChangeDependencies์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ๊ณณ์—์„œ๋Š” stream.listen ์ฝœ๋ฐฑ ๋‚ด๋ถ€์— ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ด๋Ÿฌํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ValueNotifier ์‰ฝ๊ฒŒ ๋ณ€ํ™˜ํ•˜๊ณ  ํ•จ์ˆ˜๊ฐ€ ์ด๋Ÿฌํ•œ ์•Œ๋ฆผ์„ ์ˆ˜์‹ ํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ์‚ถ์„ ํ›จ์”ฌ ๋” ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ํŒจํ„ด๋ณด๋‹ค ConditionalAnimatorBuilder ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ํ˜„์‹ค์ ์ด๊ณ  ์‰ฝ์Šต๋‹ˆ๋‹ค.

์ด์œ ์— ๋Œ€ํ•ด์„œ๋Š” context ๋Œ€์‹  StateHelper ์ด (StatelessWidget ์ž‘์—…์ฒ˜๋Ÿผ) ๋” ์œ ์—ฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค

StatelessWidget์€ ์ƒํƒœ ๋น„์ €์žฅ ์œ„์ ฏ์„ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์š”์ ์€ ๊ทธ๋“ค์ด ์ƒํƒœ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๋ฌผ๊ฑด์„ ํ๊ธฐํ•˜๊ณ , didUpdateWidget ๋“ฑ์— ๋ฐ˜์‘ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•ซ ๋ฆฌ๋กœ๋“œ๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์‹ญ์‹œ์˜ค. ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ initState์— ํด๋กœ์ €๋ฅผ ๋‘๋Š” ๋Œ€์‹  ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค.

๊ณ„์† ์ด๋Ÿฐ ๋ง์„ ํ•ด์„œ ๋ฏธ์•ˆํ•˜๊ณ , ๋‹ต๋‹ตํ•  ํ…๋ฐ๋„ ์šฐ๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์„œ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•„์ง๋„ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์›๋ž˜ ๋ฒ„๊ทธ ์š”์•ฝ๊ณผ ์›๋ž˜ ์„ค๋ช…์˜ ํฐ ๋ถ€๋ถ„์— ๋”ฐ๋ผ ์žฅํ™ฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์ง€๋งŒ ๊ทธ๊ฒŒ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์—ฌ๊ธฐ์—๋Š” ์ƒํ˜ธ ๋ฐฐํƒ€์ ์ธ ์š•๋ง์ด ๋งŽ์ด ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ์ด ๋ฒ„๊ทธ์˜ ๋งŽ์€ ๋Œ“๊ธ€์— ํผ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์–ด๋–ค ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ถ„ํ• ์ง€ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์€ ๊ทธ๊ฒƒ์„ ํ• ๋‹นํ•œ ๊ณณ๊ณผ ๊ฐ™์€ ๊ณณ์—์„œ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค...
  • ... ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์„ ํ• ๋‹นํ•˜๋Š” ์žฅ์†Œ๋Š” ๊ทธ๊ฒƒ์„ ํ• ๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค...
  • ... ๊ทธ๋ฆฌ๊ณ  ํ•ซ ๋ฆฌ๋กœ๋“œ์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์ •์˜์ƒ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์ง€ ์•Š์Œ)...
  • ...์ƒํƒœ ๋น„์ €์žฅ ์œ„์ ฏ(์ •์˜์ƒ ์ƒํƒœ๊ฐ€ ์—†์Œ)๊ณผ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋Š” ์ƒํƒœ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค...
  • ... ๊ทธ๋ฆฌ๊ณ  didUpdateWidget ๋ฐ didChangeDependencies์™€ ๊ฐ™์€ ๊ฒƒ๋“ค์— ๋Œ€ํ•œ ํ›„ํ‚น์„ ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค...

์šฐ๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์„œ ์ฐธ์—ฌํ•˜๋Š” ์ด ๋ฐ˜๋ณต์ ์ธ ์ถค์€ ์ผ์„ ๋๋‚ด๋Š” ์ƒ์‚ฐ์ ์ธ ๋ฐฉ๋ฒ•์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ „์— ๋งํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์—ฌ๊ธฐ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์–ป๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์šฐ๋ฆฌ๊ฐ€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง๋ฉดํ•œ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์š”๊ตฌ ์‚ฌํ•ญ์€ ํ•œ ๊ณณ์—์„œ ์„ค๋ช…๋˜๊ณ  ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ํ•จ๊ป˜ ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค. ์†”๋ฃจ์…˜์„ ๋‚˜์—ดํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ๊ท€ํ•˜์˜ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ๋Š” ์†”๋ฃจ์…˜์€ ๋‚˜์—ดํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์†”๋ฃจ์…˜์„ ๋ถ€์ ์ ˆํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ํ•„์š”์„ฑ์ด ์„ค๋ช…์— ๋‚˜์—ด๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

์†”์งํžˆ ๋งํ•ด์„œ ๊ทผ๋ณธ์ ์œผ๋กœ ์™„์ „ํžˆ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ ๋””์ž์ธ์„ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์™„๋ฒฝํ•˜์ง€๋งŒ Flutter๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋“ ๋‹ค๋ฉด ๊ทธ๊ฒƒ์€ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋  ๊ฒƒ์ด๊ณ , ์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ _this_ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ํ•ด์•ผ ํ•  ์ผ์ด ๋งŽ์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค, ๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ๋งŽ์€ ๋ถ€๋ถ„์ด Jetpack Compose๊ฐ€ ์„ค๊ณ„๋œ ๋ฐฉ์‹๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ปดํŒŒ์ผ๋Ÿฌ ๋งˆ๋ฒ•์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ๋””์ž์ธ์˜ ์—ด๋ ฌํ•œ ํŒฌ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ๋””๋ฒ„๊น…ํ•˜๋Š” ๊ฒƒ์€ ์ •๋ง ์–ด๋ ต์ง€๋งŒ ์•„๋งˆ๋„ ๋‹น์‹ ์˜ ๊ณจ๋ชฉ์— ๋” ๊ฐ€๊น์Šต๋‹ˆ๊นŒ?

์—ฌ๊ธฐ์—๋Š” ์ƒํ˜ธ ๋ฐฐํƒ€์ ์ธ ์š•๋ง์ด ๋งŽ์ด ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ์ด ๋ฒ„๊ทธ์˜ ๋งŽ์€ ๋Œ“๊ธ€์— ํผ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ๋“ค์€ ์ƒํ˜ธ ๋ฐฐํƒ€์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๋Š” ์ด ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์†”๋ฃจ์…˜์— ์ดˆ์ ์„ ๋งž์ถ”๊ณ  ์‹ถ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์„ธ๋ถ€ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜์ง€ ์•Š๊ฒ ์ง€๋งŒ ๋ชจ๋“  ํ™•์ธ๋ž€์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ „์— ๋งํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์—ฌ๊ธฐ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์–ป๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์šฐ๋ฆฌ๊ฐ€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง๋ฉดํ•œ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์š”๊ตฌ ์‚ฌํ•ญ์€ ํ•œ ๊ณณ์—์„œ ์„ค๋ช…๋˜๊ณ  ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ํ•จ๊ป˜ ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์•„์ง๋„ ๊ทธ ์ตœ๊ณ  ๋Œ“๊ธ€์ด ์–ด๋–ป๊ฒŒ ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ๋ชปํ•˜๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.
๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋Š” ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ๊ฒƒ์ด ๋‚˜์—๊ฒŒ๋Š” ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค, ๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ๋งŽ์€ ๋ถ€๋ถ„์ด Jetpack Compose๊ฐ€ ์„ค๊ณ„๋œ ๋ฐฉ์‹๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ปดํŒŒ์ผ๋Ÿฌ ๋งˆ๋ฒ•์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ๋””์ž์ธ์˜ ์—ด๋ ฌํ•œ ํŒฌ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ๋””๋ฒ„๊น…ํ•˜๋Š” ๊ฒƒ์€ ์ •๋ง ์–ด๋ ต์ง€๋งŒ ์•„๋งˆ๋„ ๋‹น์‹ ์˜ ๊ณจ๋ชฉ์— ๋” ๊ฐ€๊น์Šต๋‹ˆ๊นŒ?

๋‚˜๋Š” ๊ทธ๊ฒƒ์— ์ต์ˆ™ํ•˜์ง€ ์•Š์ง€๋งŒ ๋น ๋ฅธ ๊ฒ€์ƒ‰์œผ๋กœ ๋‚˜๋Š” _yes_๋ผ๊ณ  ๋งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ๋“ค์€ ์ƒํ˜ธ ๋ฐฐํƒ€์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์œ„์— ๋‚˜์—ดํ•œ ๋ชจ๋“  ๊ธ€๋จธ๋ฆฌ ๊ธฐํ˜ธ๊ฐ€ ์—ฌ๊ธฐ์—์„œ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ์˜ ์ผ๋ถ€์ž…๋‹ˆ๊นŒ?

ํ•˜์ง€๋งŒ ๊ทธ๋“ค์€ ๋ชจ๋“  ์ƒ์ž๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค

์ƒ์ž๋ฅผ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚˜๋Š” ์•„์ง๋„ ๊ทธ ์ตœ๊ณ  ๋Œ“๊ธ€์ด ์–ด๋–ป๊ฒŒ ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ๋ชปํ•˜๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด OP๋Š” ๋ฌธ์ œ๊ฐ€ StatefulWidgets์— ๊ด€ํ•œ ๊ฒƒ์ด๋ผ๊ณ  ๋ช…์‹œ์ ์œผ๋กœ ๋ฐํ˜”์ง€๋งŒ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ตœ๊ทผ ์˜๊ฒฌ ์ค‘ ํ•˜๋‚˜๋Š” ํŠน์ • ์ œ์•ˆ์ด StatelessWidgets์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ข‹์ง€ ์•Š๋‹ค๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

OP์—์„œ ๋‹น์‹ ์€ ๋งํ•ฉ๋‹ˆ๋‹ค :

State ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•˜๊ณ  ๊นŠ์ด ์ค‘์ฒฉ๋œ build ๋ฉ”์„œ๋“œ๋กœ ๋๋‚˜๊ฑฐ๋‚˜ ์—ฌ๋Ÿฌ ์œ„์ ฏ์— ๋…ผ๋ฆฌ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์š”๊ตฌ ์‚ฌํ•ญ์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • ์†”๋ฃจ์…˜์€ ๊นŠ์ด ์ค‘์ฒฉ๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.
  • ์†”๋ฃจ์…˜์€ ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ์œ„์น˜์— ์œ ์‚ฌํ•œ ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ์š”๊ตฌํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์š”์ (์ค‘์ฒฉ์— ๋Œ€ํ•œ)์€ ๊ดœ์ฐฎ์•„ ๋ณด์ž…๋‹ˆ๋‹ค. ๊นŠ์ด ๋‚ดํฌ๋œ ์ผ์„ ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ œ์•ˆํ•˜๋ ค๋Š” ๊ฒƒ์€ ์ ˆ๋Œ€ ์•„๋‹™๋‹ˆ๋‹ค. (์ฆ‰, ์šฐ๋ฆฌ๋Š” ๊นŠ์ด ์ค‘์ฒฉ๋œ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ๋™์˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์—ฌ๊ธฐ์— ์ •์˜๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค๋ฅธ ์ฃผ์„์€ ๋นŒ๋”๊ฐ€ ๊นŠ์ด ์ค‘์ฒฉ๋œ ์ฝ”๋“œ๋ฅผ ์œ ๋ฐœํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•”์‹œํ•˜์ง€๋งŒ, ์ด์ „์— ์ธ์šฉํ•œ ์ฝ”๋“œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ์ œ ๊ฒฝํ—˜์ƒ ๋นŒ๋”๋Š” ๊ฝค ์ข‹์Šต๋‹ˆ๋‹ค.)

๋‘ ๋ฒˆ์งธ ์š”์ ์€ ์šฐ๋ฆฌ๊ฐ€ ์žฅํ™ฉํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค๋Š” ์š”๊ตฌ ์‚ฌํ•ญ์„ ๋˜‘๋ฐ”๋กœ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹น์‹ ์€ ์ด๊ฒƒ์ด ์žฅํ™ฉํ•œ ๊ฒƒ์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๊ณ  ์—ฌ๋Ÿฌ ๋ฒˆ ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.

OP๊ฐ€ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๋‹ค์Œ ์ง„์ˆ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ StatefulWidget ์—์„œ State ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํ•ด๋‹น ๋…ผ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์˜์กดํ•˜๋Š” ํ•œ ๋งค์šฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์†”์งํžˆ ์ด๊ฒŒ ๋ฌด์Šจ ๋œป์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚˜์—๊ฒŒ "์–ด๋ ค์›€"์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šด ๋ณต์žกํ•œ ๋…ผ๋ฆฌ๊ฐ€ ๋งŽ์ด ํฌํ•จ๋˜์–ด ์žˆ์ง€๋งŒ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ด๋ฒคํŠธ๋ฅผ ํ• ๋‹น, ์ฒ˜๋ฆฌ ๋ฐ ๋Œ€์‘ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋‹ค์Œ ๋ฌธ์žฅ(์—ฌ๊ธฐ์„œ๋Š” "๋ณต์žกํ•˜์ง€ ์•Š์Œ"์œผ๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์„ค๋ช…๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์„ค๋ช…์ด ์•„๋‹ ์ˆ˜ ์žˆ์Œ)์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ํ•ด๋‹น ์ ‘๊ทผ ๋ฐฉ์‹์„ ํ™•์žฅํ•  ๋•Œ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ "๋งค์šฐ ์–ด๋ ต๋‹ค"๋Š” ๊ฒƒ์ด "๋งค์šฐ ์žฅํ™ฉํ•˜๋‹ค"๋ฅผ ์˜๋ฏธํ•˜๊ณ  ์œ ์‚ฌํ•œ ์ฝ”๋“œ๊ฐ€ ๋งŽ์ด ๋ฐœ์ƒํ•˜๋Š” ๋ฐ์„œ ์–ด๋ ค์›€์ด ์ƒ๊ธด๋‹ค๋Š” ๊ฒƒ์„ ์•”์‹œํ–ˆ์Šต๋‹ˆ๋‹ค. " ์˜ˆ์ œ๋ฅผ ํ™•์žฅํ•œ ๊ฒฐ๊ณผ๋Š” ๋ง ๊ทธ๋Œ€๋กœ ๋™์ผํ•œ ์ฝ”๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(์˜ˆ: ์žฅํ™ฉํ•จ, ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ).

์ด๊ฒƒ์€ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๋‹ค์Œ ๋ฌธ์žฅ์— ์˜ํ•ด ๋”์šฑ ๋’ท๋ฐ›์นจ๋ฉ๋‹ˆ๋‹ค.

์ด ๋…ผ๋ฆฌ๋ฅผ ๋ชจ๋“  ๊ณณ์— ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์œผ๋ฉด "์ž‘๋™"ํ•˜์ง€๋งŒ ์ฝ”๋“œ์— ์•ฝ์ ์ด ์ƒ๊น๋‹ˆ๋‹ค.

  • ๋‹จ๊ณ„ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆฌ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค(์˜ˆ dispose ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ์žŠ์Œ)

์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์„ ๋•Œ ์žฅํ™ฉํ•œ ํ‘œํ˜„์œผ๋กœ ์ธํ•ด ์‹ค์ˆ˜๋ฅผ ํ•˜๊ธฐ ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋งˆ๋„ ๋งค์šฐ ์–ด๋ ค์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ๋‚ด๊ฐ€ "์žฅํ™ฉํ•จ"์œผ๋กœ ์„ค๋ช…ํ•  ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ–ˆ์„ ๋•Œ, ๋‹น์‹ ์€ ๋ฌธ์ œ๊ฐ€ ์žฅํ™ฉํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์ฝ”๋“œ์— ๋งŽ์€ ๋…ธ์ด์ฆˆ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์‹œ ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์žฅํ™ฉํ•จ/๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๋ฅผ ๋งํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฌ์ง€๋งŒ, ๋‹ค์‹œ ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๊ณ  ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋จธ์ง€ OP๋Š” ๋‹น์‹ ์ด ์ข‹์•„ํ•˜์ง€ ์•Š๋Š” ์†”๋ฃจ์…˜์„ ์„ค๋ช…ํ•  ๋ฟ์ด๋ฏ€๋กœ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ OP๊ฐ€ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๊นŒ? ์‹ค์ œ๋กœ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” OP์˜ ๋ชจ๋“  ํ•ญ๋ชฉ์€ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ๊ทธ๊ฒƒ์ด ๋ฌธ์ œ๋ผ๊ณ  ์ œ์•ˆํ•  ๋•Œ๋งˆ๋‹ค ๋‹น์‹ ์€ ๊ทธ๋ ‡์ง€ ์•Š๊ณ  ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ ์˜คํ•ด๊ฐ€ ๋‹จ์–ด์˜ ์˜๋ฏธ๋กœ ๊ท€๊ฒฐ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด:

์ฝ”๋“œ์— ๋งŽ์€ ๋…ธ์ด์ฆˆ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์‹œ ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์žฅํ™ฉํ•จ/๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๋ฅผ ๋งํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฌ์ง€๋งŒ, ๋‹ค์‹œ ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๊ณ  ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ์š”์ ์€ controller.dispose() ์˜ ์ˆซ์ž๊ฐ€ ์•„๋‹ˆ๋ผ ์ด๋Ÿฌํ•œ ์ฝ”๋“œ ํ–‰์ด ๋…์ž์—๊ฒŒ ์ œ๊ณตํ•˜๋Š” ๊ฐ€์น˜์ž…๋‹ˆ๋‹ค.
๊ทธ ์„ ์€ ํ•ญ์ƒ ์žˆ์–ด์•ผ ํ•˜๋ฉฐ ํ•ญ์ƒ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋…์ž์— ๋Œ€ํ•œ ๊ฐ’์€ ๊ฑฐ์˜ null์ž…๋‹ˆ๋‹ค.

์ค‘์š”ํ•œ ๊ฒƒ์€ ์ด ์„ ์˜ ์กด์žฌ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ทธ๊ฒƒ์˜ ๋ถ€์žฌ์ด๋‹ค.

๋ฌธ์ œ๋Š” ์ด๋Ÿฌํ•œ controller.dispose() ๊ฐ€ ๋งŽ์„์ˆ˜๋ก dispose ๋ฉ”์„œ๋“œ์—์„œ ์‹ค์ œ ๋ฌธ์ œ๋ฅผ ๋†“์น  ๊ฐ€๋Šฅ์„ฑ์ด ๋” ๋†’๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
1๊ฐœ์˜ ์ปจํŠธ๋กค๋Ÿฌ์™€ 0๊ฐœ์˜ Dispose๊ฐ€ ์žˆ์œผ๋ฉด ์‰ฝ๊ฒŒ ์žก์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
100๊ฐœ์˜ ์ปจํŠธ๋กค๋Ÿฌ์™€ 99๊ฐœ์˜ ์ฒ˜๋ถ„์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋ˆ„๋ฝ๋œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ฐพ๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์„ ๋•Œ ์žฅํ™ฉํ•œ ํ‘œํ˜„์œผ๋กœ ์ธํ•ด ์‹ค์ˆ˜๋ฅผ ํ•˜๊ธฐ ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋งˆ๋„ ๋งค์šฐ ์–ด๋ ค์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ๋‚ด๊ฐ€ "์žฅํ™ฉํ•จ"์œผ๋กœ ์„ค๋ช…ํ•  ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ–ˆ์„ ๋•Œ, ๋‹น์‹ ์€ ๋ฌธ์ œ๊ฐ€ ์žฅํ™ฉํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ „ ์š”์ ์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋ชจ๋“  ์ฝ”๋“œ ํ–‰์ด ๋™์ผํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๋น„๊ตํ•œ๋‹ค๋ฉด :

+ T state;

<strong i="24">@override</strong>
void initState() {
  super.initState();
+  state = widget.valueNotifier.value;
+  widget.valueNotifier.addListener(_listener);
}

+ void _listener() => seState(() => state = widget.valueNotifier.value);

void dispose() {
+ widget.valueNotifier.removeListener(_listener);
  super.dispose();
}

๋Œ€:

+ ValueListenableBuilder<T>(
+   valueListenable: widget.valueNotifier,  
+   builder: (context, value, child) {

+    },
+ );

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ด ๋‘ ์กฐ๊ฐ์€ ๋ชจ๋‘ ๊ฐ™์€ ์ˆ˜์˜ ์ค„์„ ๊ฐ€์ง€๋ฉฐ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ValueListenableBuilder ๊ฐ€ ๋” ์ข‹์Šต๋‹ˆ๋‹ค.

๊ทธ ์ด์œ ๋Š” ์ค‘์š”ํ•œ ๊ฒƒ์€ ์ค„์˜ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ด ์ค„์ด ๋ฌด์—‡์ธ์ง€์ž…๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์Šค๋‹ˆํŽซ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • 1 ์†์„ฑ ์„ ์–ธ
  • 1 ๋ฉ”์„œ๋“œ ์„ ์–ธ
  • ๊ณผ์ œ 1๊ฐœ
  • 2 ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
  • ๋ชจ๋‘ 2๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ๊ฑธ์ณ ์žˆ์Šต๋‹ˆ๋‹ค. 3 ๋นŒ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒฝ์šฐ

๋‘ ๋ฒˆ์งธ ์Šค๋‹ˆํŽซ์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

  • 1 ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šคํ™”
  • 1 ์ต๋ช… ํ•จ์ˆ˜
  • ์ˆ˜๋ช…์ฃผ๊ธฐ ์—†์Œ. 1 ๋นŒ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒฝ์šฐ

์ด๋Š” ValueListenableBuilder๋ฅผ _๊ฐ„๋‹จํ•˜๊ฒŒ_ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์ด ํ–‰์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‚ด์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค.
ValueListenableBuilder๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋˜๋Š” valueListenable ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
widget.valueNotifier ๊ฐ€ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋„ ์šฐ๋ฆฌ๊ฐ€ ๋งํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์•„ํ”„์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์–ธ์  ๊ฐ€๋Š” ๊ทธ ๋ง์ด ๋ฐ”๋€” ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ValueListenableBuilder๋Š” ์ƒˆ ๋™์ž‘์„ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ ์ฒซ ๋ฒˆ์งธ ์Šค๋‹ˆํŽซ์—๋Š” ์ด์ œ ๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ValueListenableBuilder๋Š” ๋” ๊ฐ„๋‹จํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ •ํ™•ํžˆ ๊ฐ™์€ ์ˆ˜์˜ ๋ผ์ธ์— ๋Œ€ํ•ด ์ฝ”๋“œ ๋ณ€๊ฒฝ์— ๋” ํƒ„๋ ฅ์ ์ž…๋‹ˆ๋‹ค.


์ด๋ฅผ ํ†ตํ•ด ValueListenableBuilder๊ฐ€ ๋” ๋‚ซ๋‹ค๋Š” ๋ฐ ๋‘˜ ๋‹ค ๋™์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ ๋‹ค์Œ ์งˆ๋ฌธ์€ "๋ชจ๋“  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๋…ผ๋ฆฌ์— ๋Œ€ํ•ด ValueListenableBuilder์— ํ•ด๋‹นํ•˜๋Š” ๊ฒƒ์ด ์—†๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?"์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ๋Œ€์‹ :

final controller = TextEditingController(text: 'hello world');
...
controller.dispose();

์šฐ๋ฆฌ๋Š”ํ•ด์•ผ:

TextEditingControllerBuilder(
  initialText: 'hello world',
  builder: (context, controller) {

  },
);

initialText ๋ณ€๊ฒฝํ•˜๋ฉด ํ•ซ ๋ฆฌ๋กœ๋“œ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์ถ”๊ฐ€ ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์˜ˆ์ œ๋Š” ์•ฝ๊ฐ„ ์‚ฌ์†Œํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์•ฝ๊ฐ„ ๋” ๊ณ ๊ธ‰ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๋…ผ๋ฆฌ(์˜ˆ: ModeratorBuilder )์— ์ด ์›์น™์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ž‘์€ ์กฐ๊ฐ์—์„œ "์ •์ƒ"์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ ‘๊ทผ ๋ฐฉ์‹์„ ํ™•์žฅํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

  • ๊ฑด์ถ•์—…์ž๋Š” "๋„ˆ๋ฌด ๋งŽ์€ ์†Œ์Œ" ๋ฌธ์ œ๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์–ด๋–ค ์‚ฌ๋žŒ๋“ค์ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ชจ๋ธ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

class User {
  final ValueNotifier<String> name;
  final ValueNotifier<int> age;
  final ValueNotifier<Gender> gender;
}

๊ทธ๋Ÿฌ๋‚˜ ์œ„์ ฏ์€ name , age ๋ฐ gender ๋ชจ๋‘๋ฅผ ํ•œ ๋ฒˆ์— ๋ชจ๋‘ ์ˆ˜์‹ ํ•˜๋ ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ฆ‰, ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

return ValueListenableBuilder<String>(
  valueListenable: user.name,
  builder: (context, userName, _) {
    return ValueListenableBuilder<int>(
      valueListenable: user.age,
      builder: (context, userAge, _) {
        return ValueListenableBuilder<Gender>(
          valueListenable: user.gender,
          builder: (context, userGender, _) {
            return Text('$userGender. $userName ($userAge)');
          },
        );
      },
    );
  },
);

์ด๊ฒƒ์€ ๋ถ„๋ช…ํžˆ ์ด์ƒ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. build ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค์—ผ์‹œํ‚ค๊ธฐ ์œ„ํ•ด initState / dispose ๋‚ด๋ถ€์˜ ์˜ค์—ผ์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค.

(์˜ˆ์‹œ๋ฅผ ์œ„ํ•ด Listenable.merge ๋Š” ๋ฌด์‹œํ•ฉ์‹œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

Builders๋ฅผ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ์ด ์ •ํ™•ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์šฐ๋ฆฌ ์ž์‹ ์„ ์‰ฝ๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Listenable.merge ํ•ด๋‹นํ•˜๋Š” ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉ์ž ์ •์˜ ๋นŒ๋”๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ์ง€๋ฃจํ•ฉ๋‹ˆ๋‹ค.

    ๋นŒ๋”๋ฅผ ๋งŒ๋“œ๋Š” ์‰ฌ์šด ์†”๋ฃจ์…˜์€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฆฌํŒฉํ† ๋ง ๋„๊ตฌ๋Š” ์—ฌ๊ธฐ์—์„œ ์šฐ๋ฆฌ๋ฅผ ๋„์šธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” "๋นŒ๋”๋กœ ์ถ”์ถœ"ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
    ๋˜ํ•œ, ๋ฐ˜๋“œ์‹œ ์ง๊ด€์ ์ผ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜ ๋นŒ๋”๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ์‚ฌ๋žŒ๋“ค์ด ๊ฐ€์žฅ ๋จผ์ € ์ƒ๊ฐํ•  ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŠนํžˆ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์ƒ์šฉ๊ตฌ์— ๋ฐ˜๋Œ€ํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—(์ €๋Š” ์•„๋‹™๋‹ˆ๋‹ค).

    ์‚ฌ๋žŒ๋“ค์€ ๋งž์ถคํ˜• ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค๊ณ  ์ž ์žฌ์ ์œผ๋กœ ์ž˜๋ชป๋œ ์ฝ”๋“œ๋กœ ๋๋‚  ๊ฐ€๋Šฅ์„ฑ์ด ๋” ํฝ๋‹ˆ๋‹ค.

  • Builders์˜ ํŠธ๋ฆฌ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๊ฒƒ์€ ์ง€๋ฃจํ•ฉ๋‹ˆ๋‹ค.

    ์ด์ „ ์˜ˆ์—์„œ ValueListenableBuilder ๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ์ƒˆ ๊ฒƒ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์‰ฝ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    ์šฐ๋ฆฌ ์ฝ”๋“œ๊ฐ€ ์ปดํŒŒ์ผ๋˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡ ๋ถ„ ๋™์•ˆ () ๋ฐ {}๋ฅผ ์„ธ๋Š” ๋ฐ ์‹œ๊ฐ„์„ ํ• ์• ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


ํ›„ํฌ๋Š” ๋ฐฉ๊ธˆ ์–ธ๊ธ‰ํ•œ ๋นŒ๋” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด์ „ ์˜ˆ์ œ๋ฅผ ํ›„ํฌ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฉ๋‹ˆ๋‹ค.

final userName = useValueListenable(user.name);
final useAge = useValueListenable(user.age);
final useGender = useValueListenable(user.gender);

return Text('$userGender. $userName ($userAge)');

์ด์ „ ๋™์ž‘ ๊ณผ ๋™์ผ ํ•˜์ง€๋งŒ ์ด์ œ ์ฝ”๋“œ์— ์„ ํ˜• ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋Š” ๋‹ค์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
  • ํŽธ์ง‘ํ•˜๊ธฐ๊ฐ€ ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค. (){}๋ฅผ ๋‘๋ ค์›Œํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ƒˆ ์ค„์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

provider ์ด(๊ฐ€) ์ข‹์•„ํ•˜๋Š” ์ฃผ์š” ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. MultiProvider ๋ฅผ ๋„์ž…ํ•˜์—ฌ ๋งŽ์€ ์ค‘์ฒฉ์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ initState / dispose ์ ‘๊ทผ ๋ฐฉ์‹๊ณผ ๋‹ฌ๋ฆฌ ํ•ซ ๋ฆฌ๋กœ๋“œ์˜ ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ƒˆ๋กœ์šด useValueListenable ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์ฆ‰์‹œ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋ฌผ๋ก  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ์ถ”์ถœํ•˜๋Š” ๊ธฐ๋Šฅ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์žˆ์Šต๋‹ˆ๋‹ค.

String useUserLabel(User user) {
  final userName = useValueListenable(user.name);
  final useAge = useValueListenable(user.age);
  final useGender = useValueListenable(user.gender);

  return '$userGender. $userName ($userAge)';
}

Widget build(context) {
  final label = useUserLabel(user);
  return Text(label);
}

์ด๋Ÿฌํ•œ ๋ณ€๊ฒฝ์€ ๋Œ€๋ถ€๋ถ„์˜ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์ž‘๋™ํ•˜๋Š” extract as function ๋กœ ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๊ทธ๊ฒƒ์ด ๋‹น์‹ ์˜ ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•ฉ๋‹ˆ๊นŒ?

ํ™•์‹ ํ•˜๋Š”. ํ•˜์ง€๋งŒ ์ด์™€ ๊ฐ™์€ ๋ฌธ์ œ์˜ ๋ฌธ์ œ๋Š” ์‹ค์ œ๋กœ ์˜ฌ๋ฐ”๋ฅธ ์ผ์„ ํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•œ ์ •๋ณด๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

Widget build(context) {
  if (random.nextBool())
    final title = useLabel(title);
  final label = useLabel(name);
  return Text(label);
}

...์ •๋ง ํ˜ผ๋ž€์Šค๋Ÿฌ์šด ๋ฐฉ์‹์œผ๋กœ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ปดํŒŒ์ผ๋Ÿฌ ๋งˆ๋ฒ•(Compose๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ์‹)์œผ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ Flutter์˜ ๊ฒฝ์šฐ ๊ธฐ๋ณธ ์„ค๊ณ„ ๊ฒฐ์ • ์ค‘ ์ผ๋ถ€๋ฅผ ์œ„๋ฐ˜ํ•ฉ๋‹ˆ๋‹ค. ํ‚ค๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ์ €ํ•˜๋ฉ๋‹ˆ๋‹ค(๋ณ€์ˆ˜ ์กฐํšŒ๊ฐ€ ๋งต ์กฐํšŒ, ํ•ด์‹œ ๋“ฑ์„ ํฌํ•จํ•˜๊ธฐ ๋•Œ๋ฌธ์—). ์ด๋Š” Flutter์˜ ๊ธฐ๋ณธ ์„ค๊ณ„ ๋ชฉํ‘œ ์ค‘ ์ผ๋ถ€๋ฅผ ์œ„๋ฐ˜ํ•ฉ๋‹ˆ๋‹ค.

์•ž์„œ ์ œ์•ˆํ•œ Property ์†”๋ฃจ์…˜ ๋˜๋Š” ๊ทธ์—์„œ ํŒŒ์ƒ๋œ ์†”๋ฃจ์…˜์€ ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ํ•œ ๊ณณ์—์„œ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•œ ๋ชฉํ‘œ๋ฅผ ๊ณ„์† ๋‹ฌ์„ฑํ•˜๋ฉด์„œ ์ปดํŒŒ์ผ๋Ÿฌ์˜ ๋งˆ๋ฒ•์„ ํ”ผํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ์™œ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”์ง€ ์ •๋ง๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. (๋ถ„๋ช…ํžˆ ๊ทธ๊ฒƒ์€ ์™„์ „ํ•œ ์†”๋ฃจ์…˜์ด ๋˜๋„๋ก didChangeDependencies ๋“ฑ์— ์—ฐ๊ฒฐํ•˜๋„๋ก ํ™•์žฅ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.) (์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์ด ์šฐ๋ฆฌ์˜ ์„ฑ๋Šฅ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์œ„๋ฐ˜ํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๊ธฐ๋ณธ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋„ฃ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

๋ฐ”๋กœ ๋‹น์‹ ์ด ๋งํ–ˆ๋“ฏ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ„๊ทธ๋กœ ์ธํ•ด ํ›„ํฌ๊ฐ€ ์กฐ๊ฑด๋ถ€๋กœ ํ˜ธ์ถœ๋˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ReactJS์˜ Rules of Hooks ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. ๊ธฐ๋ณธ ์š”์ ์€ ๊ตฌํ˜„ ์‹œ ํ˜ธ์ถœ ์ˆœ์„œ๋กœ ์ถ”์ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์กฐ๊ฑด๋ถ€๋กœ ์‚ฌ์šฉํ•˜๋ฉด ํ˜ธ์ถœ ์ˆœ์„œ๊ฐ€ ๊นจ์ ธ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ถ”์ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ›„ํฌ๋ฅผ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์กฐ๊ฑด ๋…ผ๋ฆฌ ์—†์ด build ์˜ ์ตœ์ƒ์œ„ ์ˆ˜์ค€์—์„œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. JS ๋ฒ„์ „์—์„œ๋Š” ๋‹ค์‹œ

const [title, setTitle] = useLabel("title");

Dart๋Š” ๋น„์Šทํ•  ์ˆ˜ ์žˆ์ง€๋งŒ JS์ฒ˜๋Ÿผ ์••์ถ•์„ ํ’€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋” ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var titleHook = useLabel("title");
String title = titleHook.property;
Function setTitle = titleHook.setter;

์กฐ๊ฑด๋ถ€ ๋…ผ๋ฆฌ๋ฅผ ์›ํ•˜๋ฉด _์ตœ์ƒ์œ„ ์ˆ˜์ค€์—์„œ ํ˜ธ์ถœํ•œ ํ›„ ๋นŒ๋“œ ๋ฉ”์„œ๋“œ์—์„œ title ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ํ˜ธ์ถœ ์ˆœ์„œ๊ฐ€ ์—ฌ์ „ํžˆ ์œ ์ง€๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ท€ํ•˜๊ฐ€ ์ œ๊ธฐํ•œ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ ์ค‘ ๋งŽ์€ ๋ถ€๋ถ„์ด ์œ„์— ๋งํฌ๋œ ํ›„ํฌ ๋ฌธ์„œ์— ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ™•์‹ ํ•˜๋Š”. ๊ทธ๋ฆฌ๊ณ  ๋‹น์‹ ์€ ํŒจํ‚ค์ง€์—์„œ ๊ทธ๊ฒƒ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์ข…๋ฅ˜์˜ ์š”๊ตฌ ์‚ฌํ•ญ์€ ์šฐ๋ฆฌ์˜ ๋””์ž์ธ ์ฒ ํ•™์„ ์œ„๋ฐ˜ํ•  ๊ฒƒ์ด๋ฏ€๋กœ Flutter ํ”„๋ ˆ์ž„์›Œํฌ์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. (ํŠนํžˆ, ์šฐ๋ฆฌ๋Š” ๊ฐ€๋…์„ฑ๊ณผ ๋””๋ฒ„๊น… ๊ฐ€๋Šฅ์„ฑ์„ ์œ„ํ•ด ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์กฐ๊ฑด๋ถ€(์ฝ”๋“œ์—์„œ ๋ช…ํ™•ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ) ๋•Œ๋ฌธ์— ๋•Œ๋•Œ๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ฝ”๋“œ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ ๊ถŒ์žฅํ•˜๊ฑฐ๋‚˜ ํ™œ์„ฑํ™”ํ•˜๋ ค๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ.)

๋””๋ฒ„๊น…/์กฐ๊ฑด๋ถ€ ๋™์ž‘์€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ถ„์„๊ธฐ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • ํ•จ์ˆ˜๊ฐ€ useMyFunction ๋ผ๋Š” ์ด๋ฆ„ ์—†์ด ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๊ฒฝ๊ณ 
  • ํ›„ํฌ๊ฐ€ ์กฐ๊ฑด๋ถ€๋กœ ์‚ฌ์šฉ๋˜๋ฉด ๊ฒฝ๊ณ 
  • ๋ฃจํ”„/์ฝœ๋ฐฑ์—์„œ ํ›„ํฌ๊ฐ€ ์‚ฌ์šฉ๋˜๋ฉด ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋ชจ๋“  ์ž ์žฌ์ ์ธ ์‹ค์ˆ˜๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค. React๋Š” ์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ ์ผ์ž„์„ ์ฆ๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋” ์ฝ๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ(์ด์ „์— ํ‘œ์‹œ๋œ ๋Œ€๋กœ)
  • ๋” ๋‚˜์€ ํ•ซ ๋ฆฌ๋กœ๋“œ
  • ์žฌ์‚ฌ์šฉ/๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ
  • ๋” ์œ ์—ฐํ•˜๊ฒŒ - ๊ณ„์‚ฐ๋œ ์ƒํƒœ๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์‚ฐ๋œ ์ƒํƒœ์— ๋Œ€ํ•ด ํ›„ํฌ๋Š” ๊ฐœ์ฒด์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์บ์‹œํ•˜๋Š” ๋ฐ ๋งค์šฐ ๊ฐ•๋ ฅํ•ฉ๋‹ˆ๋‹ค. ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ์œ„์ ฏ์„ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Example extends HookWidget {
  final int userId;

  Widget build(context) {
    // Calls fetchUser whenever userId changes
    // It is the equivalent to both initState and didUpdateWidget
    final future = useMemo1(() => fetchUser(userId), userId);

    final snapshot = useFuture(future);
    if (!snapshot.hasData)
      return Text('loading');
    return Text(snapshot.data.name);
  }  
}

์ด๋Ÿฌํ•œ useMemo ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์„ ์‰ฝ๊ฒŒ ์ตœ์ ํ™”ํ•˜๊ณ  init + update๋ฅผ ์„ ์–ธ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ฒ„๊ทธ๋„ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ Property / context.onDispose ์ œ์•ˆ์—์„œ ๋†“์น˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋กœ์ง์„ ๋ผ์ดํ”„ ์‚ฌ์ดํด์— ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•˜๊ฑฐ๋‚˜ ValueNotifier ์ฝ”๋“œ๋ฅผ ๋ณต์žกํ•˜๊ฒŒ ํ•˜์ง€ ์•Š์œผ๋ฉด ์„ ์–ธ์  ์ƒํƒœ์— ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

ValueGetter ์ œ์•ˆ์ด ์‹ค์šฉ์ ์ด์ง€ ์•Š์€ ์ด์œ ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐ:

์šฐ๋ฆฌ๋Š” ๋ฆฌํŒฉํ† ๋ง์„ ์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

final int userId;

Widget build(context) {
  final future = useMemo1(() => fetchUser(userId), userId);

์•ˆ์œผ๋กœ:

Widget build(context) {
  final userId = Model.of(context).userId;
  final future = useMemo1(() => fetchUser(userId), userId);

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด useMemo ๊ฐ€ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด ๋ณ€๊ฒฝ์ด ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ Property + ValueGetter Property ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด Property ์ฝ”๋“œ๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์žฌ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ๋‹ค์‹œ ํ•œ๋ฒˆ ์žฌ์‚ฌ์šฉ์„ฑ์„ ์žƒ์—ˆ์Šต๋‹ˆ๋‹ค.

FWIW ์ด ์Šค๋‹ˆํŽซ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

class Example extends StatefulWidget {
  final int userId;
  <strong i="45">@override</strong>
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  Future<User> future;

  <strong i="46">@override</strong>
  void initState() {
    super.initState();
    future = fetchUser(widget.userId);
  }

  <strong i="47">@override</strong>
  void didUpdateWidget(Example oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.userId != widget.userId) {
      future = fetchUser(widget.userId);
    }
  }

  <strong i="48">@override</strong>
  Widget build(BuildContext context) {
    return FutureBuilder<User>(
      future: future,
      builder: (context, snapshot) {
        if (!snapshot.hasData)
          return Text('loading');
        return Text(snapshot.data.name);
      },
    );
  }
}

@rrousselGit์ด ์–ธ๊ธ‰ํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€๋งŒ ๊ฐ€๋…์„ฑ๊ณผ ๋””๋ฒ„๊น… ๊ฐ€๋Šฅ์„ฑ๋„ ์—ผ๋‘์— ๋‘” ์†”๋ฃจ์…˜์„ ์ฐพ์•„์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. Vue์—๋Š” ์กฐ๊ฑด๋ถ€ ๋˜๋Š” ํ˜ธ์ถœ ์ˆœ์„œ๊ฐ€ React์™€ ๊ฐ™์€ ๋ฒ„๊ทธ๋ฅผ ์ผ์œผํ‚ค์ง€ ์•Š๋Š” ๊ณณ์—์„œ ์ฐพ๊ณ  ์žˆ๋Š” ๊ฒƒ๊ณผ ๋” ์ผ์น˜ํ•  ์ˆ˜ ์žˆ๋Š” ์ž์ฒด ๊ตฌํ˜„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋งˆ๋„ ๋‹ค์Œ ๋‹จ๊ณ„๋Š” Vue๊ฐ€ Vue์˜ ์ œ์•ฝ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ฒ„์ „์„ ๋งŒ๋“  ๊ฒƒ์ฒ˜๋Ÿผ Flutter์˜ ์ œ์•ฝ ์กฐ๊ฑด์ด ์ฃผ์–ด์ง€๋ฉด ์ด ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํ›„ํฌ ๋ฒ„์ „์ธ Flutter ๊ณ ์œ ์˜ ์†”๋ฃจ์…˜์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” React์˜ ํ›„ํฌ๋ฅผ ์ •๊ธฐ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉฐ ๋•Œ๋•Œ๋กœ ๋ถ„์„๊ธฐ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๊ฐ–๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ์–ธ์–ด์— ๋” ํ†ตํ•ฉ๋˜์–ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์–ด์จŒ๋“ , ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ํ•ฉ์˜์— ๋„๋‹ฌํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์—๋„ ๋™์˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋ง์”€๋“œ๋ฆฌ์ง€๋งŒ ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์ด ๋ฌธ์ œ์™€ ๊ด€๋ จ๋œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ Flutter๊ฐ€ ์ด๊ฒƒ์— ๋Œ€ํ•ด ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์•„๋„ ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค.

  • ์ ์ ˆํ•œ ๋ถ„์„๊ธฐ ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ
  • ๋‹คํŠธํŒจ๋“œ ๋‚ด์—์„œ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ

๋‚ด๊ฐ€ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๊ถŒ์žฅํ•˜๋Š” ํ›„ํฌ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€๋งŒ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋ฌธ์ œ๋ฅผ ์ œ์ถœํ•˜๊ณ  ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด PR์„ ์ œ์ถœํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋‹น์‹ ๊ณผ ํ•จ๊ป˜ ์ผํ•˜๊ฒŒ ๋œ ๊ฒƒ์„ ๊ธฐ์˜๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์ด์ „ Property ์•„์ด๋””์–ด์˜ ์ƒˆ ๋ฒ„์ „์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ didUpdateWidget ๋ฐ ํ๊ธฐ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  didChangeDependencies์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๊ฒƒ๋“ค์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). ํ•ซ ๋ฆฌ๋กœ๋“œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค(์†์„ฑ ๋ฐ ํ•ซ ๋ฆฌ๋กœ๋“œ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์˜ฌ๋ฐ”๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค). ๋ช…์‹œ์  ์œ ํ˜•์ด ํ•„์š”ํ•˜์ง€ ์•Š๊ณ  ์œ ํ˜•์ด ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค(์ถ”๋ก ์— ์˜์กด). ์†์„ฑ ์„ ์–ธ๊ณผ ์‚ฌ์šฉ๋ฒ•์„ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋“  ๊ฒƒ์ด ํ•œ ๊ณณ์— ์žˆ์œผ๋ฉฐ ์„ฑ๋Šฅ์€ ํ•ฉ๋ฆฌ์ ์œผ๋กœ ์ข‹์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋” ์ž์„ธํ•œ ์ž‘์—… ๋ฐฉ์‹๋งŒํผ ์ข‹์ง€๋Š” ์•Š์ง€๋งŒ).

์†์„ฑ/์†์„ฑ ๊ด€๋ฆฌ์ž:

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

typedef InitStateCallback<T> = T Function(T oldValue);
typedef DidUpdateWidgetCallback<T, W extends StatefulWidget> = T Function(W oldWidget);

class Property<T, W extends StatefulWidget> {
  Property({
    T value,
    this.initState,
    this.didUpdateWidget,
    this.dispose,
  }) : _value = value;

  T get value {
    assert(_value != null);
    return _value;
  }
  T _value;

  final InitStateCallback<T> initState;
  void _initState(Property<T, W> oldProperty) {
    if (initState != null)
      _value = initState(oldProperty?.value);
    assert(_value != null);
  }

  final DidUpdateWidgetCallback<T, W> didUpdateWidget;
  void _didUpdateWidget(StatefulWidget oldWidget) {
    if (didUpdateWidget != null) {
      final T newValue = didUpdateWidget(oldWidget);
      if (newValue != null)
        _value = newValue;
    }
  }

  final ValueSetter<T> dispose;
  void _dispose() {
    if (dispose != null)
      dispose(value);
  }
}

mixin PropertyManager<W extends StatefulWidget> on State<W> {
  final Set<Property<Object, W>> _properties = <Property<Object, W>>{};
  bool _ready = false;

  Property<T, W> register<T>(Property<T, W> oldProperty, Property<T, W> property) {
    assert(_ready);
    if (oldProperty != null) {
      assert(_properties.contains(oldProperty));
      _properties.remove(oldProperty);
    }
    assert(property._value == null);
    property._initState(oldProperty);
    _properties.add(property);
    return property;
  }

  <strong i="9">@override</strong>
  void initState() {
    super.initState();
    _ready = true;
    initProperties();
  }

  <strong i="10">@override</strong>
  void reassemble() {
    super.reassemble();
    initProperties();
  }

  <strong i="11">@protected</strong>
  <strong i="12">@mustCallSuper</strong>
  void initProperties() { }

  <strong i="13">@override</strong>
  void didUpdateWidget(W oldWidget) {
    super.didUpdateWidget(oldWidget);
    for (Property<Object, W> property in _properties)
      property._didUpdateWidget(oldWidget);
  }

  <strong i="14">@override</strong>
  void dispose() {
    _ready = false;
    for (Property<Object, W> property in _properties)
      property._dispose();
    super.dispose();
  }
}

์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import 'properties.dart';

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

class MyApp extends StatelessWidget {
  <strong i="18">@override</strong>
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Example(userId: 1),
    );
  }
}

class User {
  User(this.name);
  final String name;
}

Future<User> fetchUser(int userId) async {
  await Future.delayed(const Duration(seconds: 2));
  return User('user$userId');
}

class Example extends StatefulWidget {
  Example({ Key key, this.userId }): super(key: key);

  final int userId;

  <strong i="19">@override</strong>
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> with PropertyManager {
  Property future;

  <strong i="20">@override</strong>
  void initProperties() {
    super.initProperties();
    future = register(future, Property(
      initState: (_) => fetchUser(widget.userId),
      didUpdateWidget: (oldWidget) {
        if (oldWidget.userId != widget.userId)
          return fetchUser(widget.userId);
      }
    ));
  }

  <strong i="21">@override</strong>
  Widget build(BuildContext context) {
    return FutureBuilder<User>(
      future: future.value,
      builder: (context, snapshot) {
        if (!snapshot.hasData) return Text('loading');
        return Text(snapshot.data.name);
      },
    );
  }
}

ํŽธ์˜๋ฅผ ์œ„ํ•ด AnimationController ๋“ฑ๊ณผ ๊ฐ™์€ ๊ฒƒ์— ๋Œ€ํ•ด ์ค€๋น„๋œ Property ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

State.build ๋ฉ”์†Œ๋“œ์—์„œ๋„ ์ž‘๋™ํ•˜๋Š” ๋ฒ„์ „์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค...

@Hixie ๊ฐ€ ํ…Œ์ด๋ธ”์— ๊ฐ€์ ธ์˜ค๋Š” ๋ช‡ ๊ฐ€์ง€ ์˜์‹ฌ์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ•œํŽธ์œผ๋กœ๋Š” Hooks๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ถ„๋ช…ํ•œ ์žฅ์ ์„ ๋ณด์•˜๊ณ  ๊ฝค ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด ๊ทธ๊ฒƒ์„ ์ข‹์•„ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
@timsneath๊ฐ€ ์ œ์•ˆํ•œ ํŒจํ‚ค์ง€ ์ ‘๊ทผ ๋ฐฉ์‹์— ๋Œ€ํ•œ ๋‚ด ๋ฌธ์ œ๋Š” Hooks๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ Hooks๊ฐ€ ์—†๋Š” ์ฝ”๋“œ์™€ ํฌ๊ฒŒ ๋‹ค๋ฅด๊ฒŒ ๋ณด์ธ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋“ค์ด ๊ณต์‹ ์นด๋…ผ์— ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์šฐ๋ฆฌ๋Š” Flutter ์นด๋…ผ์„ ๋”ฐ๋ฅด๋Š” ์‚ฌ๋žŒ๋“ค์ด ์ฝ์„ ์ˆ˜ ์—†๋Š” Flutter ์ฝ”๋“œ๋กœ ๋๋‚  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
ํŒจํ‚ค์ง€๊ฐ€ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์‘๋‹ต ๊ฐ€๋Šฅ์„ฑ์ด ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด ์ƒˆ๋กœ์šด ์ฝ”๋“œ ๊ธฐ๋ฐ˜์„ ๋ฐฐ์šฐ๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“œ๋Š” ๋‹ค์–‘ํ•œ Flutter ๋ฐฉ์–ธ์„ ์–ป๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ €๋Š” ์•„๋งˆ๋„ Flutter์˜ ์ผ๋ถ€๊ฐ€ ๋˜๋Š” ์ˆœ๊ฐ„ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ์€ ๋™๊ฒฐ๋œ ํŒจํ‚ค์ง€์— ๋Œ€ํ•œ ๋‚˜์˜ ํ˜„์žฌ ๊ฒฌํ•ด์™€ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ ๊ธฐ๋Šฅ์„ ์ข‹์•„ํ•˜์ง€๋งŒ Union๊ณผ ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค๊ฐ€ Dart์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹Œ ํ•œ ์‚ฌ๋žŒ๋“ค์ด ๋‚ด ์ฝ”๋“œ๋ฅผ ์ฝ๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด ์ฝ”๋“œ ๊ธฐ๋ฐ˜์— ํฌํ•จํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@escamoteur ๊ทธ๋ƒฅ ์ดํ•ดํ•˜๋Š”๋ฐ, ์œ„์ ฏ์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์„ ๊ทผ๋ณธ์ ์œผ๋กœ

์ œ์•ˆ๋œ ๋ณ€๊ฒฝ ์ž์ฒด์— ๋Œ€ํ•œ ๋Œ€ํ™”์™€ ์ง๊ตํ•˜์ง€๋งŒ @escamoteur , @rrousselGit ๋ฐ ์—ฌ๊ธฐ์™€ ๋‹ค๋ฅธ ๊ณณ์—์„œ ๋“ค์€ ๊ฒƒ์€ ํ”„๋ ˆ์ž„์›Œํฌ์— ์žˆ๋Š” ๊ฒƒ์ด ํŠน์ • ๋ณ€๊ฒฝ์˜ ํ•ฉ๋ฒ•์„ฑ์„ ํ™•๋ฆฝํ•˜๋Š” ์ค‘์š”ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ธ์‹๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ ‘๊ทผํ•˜๋‹ค. ๋™์˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์ €๋ฅผ ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค.

๋‚˜๋Š” ๊ทธ ์ƒ๊ฐ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๋งŽ์€ ๊ฒƒ์ด ๋‚˜์˜ค๊ธฐ ๋•Œ๋ฌธ์—(์˜ˆ: DartPad๋Š” ์˜ค๋Š˜๋‚  ํƒ€์‚ฌ ํŒจํ‚ค์ง€๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ถ€ ๊ณ ๊ฐ์€ NPM์œผ๋กœ ๊ตฌ์šด ํ›„ ์˜์กดํ•˜๋Š” ํŒจํ‚ค์ง€ ์ˆ˜์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•ฉ๋‹ˆ๋‹ค. ๋” '๊ณต์‹์ '์ธ ๋Š๋‚Œ์ด ๋“ค๋ฉฐ null-safety์™€ ๊ฐ™์€ ๋ณ€๊ฒฝ์œผ๋กœ ์•ž์œผ๋กœ ๋‚˜์•„๊ฐˆ ๊ฒƒ์ด ๋ณด์žฅ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ํฌํ•จํ•˜๋Š” ๋ฐ์—๋Š” ์ƒ๋‹นํ•œ ๋น„์šฉ์ด ์†Œ์š”๋ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์ ‘๊ทผ ๋ฐฉ์‹๊ณผ API๋ฅผ ๊ณจํ™”์‹œํ‚ต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ ๋‘˜ ๋‹ค ์šฐ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋งค์šฐ ๋†’์€ ๊ธฐ์ค€์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ๋งŒ์žฅ์ผ์น˜๋กœ ๋™์˜ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ(๊ตญ๊ฐ€ ๊ด€๋ฆฌ ์ฐธ์กฐ), ์ง„ํ™”์˜ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋˜๋Š” ํŒจํ‚ค์ง€์ฒ˜๋Ÿผ ์‰ฝ๊ฒŒ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

ํŒจํ‚ค์ง€ ์šฐ์„  ์ฒ ํ•™์„ ๋ฌธ์„œํ™”ํ•ด์•ผ ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‹ค์‹œ _์–ด๋””์—_๊ฐ€๋Š” ๊ฒƒ์€ ์ƒํƒœ ๋…ผ๋ฆฌ ์žฌ์‚ฌ์šฉ์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” _๋ฌด์—‡_์— ๋Œ€ํ•œ ๋…ผ์˜์™€ ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค.

ํŒจํ‚ค์ง€ ์ •์ฑ…์€ https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#deciding -where-to-put-code์— ๋ฌธ์„œํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ํŒจํ‚ค์ง€ ์šฐ์„  ์ ‘๊ทผ ๋ฐฉ์‹์„ ์ถฉ๋ถ„ํžˆ ์ดํ•ดํ•˜๊ณ  ๊ทธ๊ฒƒ์ด ์ค‘์š”ํ•œ ์ผ์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์ผ๋ถ€ ๋ฌธ์ œ๋Š” ํŒจํ‚ค์ง€๊ฐ€ ์•„๋‹ˆ๋ผ ํ•ต์‹ฌ์—์„œ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋‚ด๊ฐ€ provider ๋ฅผ Flutter์— ๋ณ‘ํ•ฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ฃผ์žฅํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ด ๋ฌธ์ œ๊ฐ€ Flutter๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•œ๋‹ค๊ณ  ๋ฏฟ๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค(๋ฌผ๋ก  ํ›„ํฌ๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹˜).

Provider์™€ ํ•จ๊ป˜ Flutter๋Š” ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ๋ณธ ์ œ๊ณต๋˜๋Š” ๊ธฐ๋ณธ ์ œ๊ณต๋˜๋Š” InheritedWidgets๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
๊ณต๊ธ‰์ž๋Š” ์ƒ๋‹จ์— ์˜๊ฒฌ์ด ์žˆ๋Š” ๋ ˆ์ด์–ด๋งŒ ์ถ”๊ฐ€ํ•˜์—ฌ ""๋” ๋ฉ‹์ง€๊ฒŒ"" ๋งŒ๋“ญ๋‹ˆ๋‹ค.

ํ›„ํฌ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ์›์‹œ์ ์ž…๋‹ˆ๋‹ค. ํŠน์ • ๋ฌธ์ œ์— ๋Œ€ํ•œ ์˜๊ฒฌ์ด ์—†๋Š” ์ €์ˆ˜์ค€ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ์ƒํƒœ์—์„œ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ๋“ค์€ ์ตœ์ข… ์ œํ’ˆ์ด ์•„๋‹ˆ์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉ์ž ์ •์˜ ํŒจํ‚ค์ง€๋ฅผ ๋นŒ๋“œํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(์˜ˆ: ๋‚ด๊ฐ€ hooks_riverpod์—์„œ ํ–ˆ๋˜

์œ„์—์„œ ๋‚ด๊ฐ€ ๋‚™์„œํ•œ ์†์„ฑ ์ ‘๊ทผ ๋ฐฉ์‹์ด ํ›„ํฌ์™€ ์–ด๋–ป๊ฒŒ ๋น„๊ต๋˜๋Š”์ง€์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๊ฒ€ํ† ๋ฅผ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด (์—ฌ๊ธฐ์—์„œ ์›ํ•˜๋Š” ๋ฐ”๋ฅผ ์ดํ•ดํ•˜๊ณ  ํ›„ํฌ๊ฐ€ ์ถฉ์กฑํ•˜๋Š” ์š”๊ตฌ ์‚ฌํ•ญ ๋“ฑ์„ ์ดํ•ดํ•˜๋Š” ์ธก๋ฉด์—์„œ) ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. (Property ์•„์ด๋””์–ด์— ๋Œ€ํ•œ ๋‚˜์˜ ๋ชฉํ‘œ๋Š” ์—ฌ๋Ÿฌ ์ƒํƒœ์—์„œ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋ ˆ์ž„์›Œํฌ ์œ„์— ์˜๊ฒฌ์„ ์Œ“๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

์†์„ฑ ์ œ์•ˆ์ด ์ด ๋ฌธ์ œ์˜ ํ•ต์‹ฌ ๋ชฉํ‘œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์‹คํŒจํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ƒํƒœ ๋…ผ๋ฆฌ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์–ด๋””์—์„œ ์˜ค๊ณ  ์–ด๋–ค ์ƒํ™ฉ์—์„œ ์—…๋ฐ์ดํŠธ๋˜๋Š”์ง€ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ์ œ์•ˆ์€ ๋ชจ๋“  ๋…ผ๋ฆฌ๋ฅผ ํ•œ ๊ณณ์—์„œ ์žฌ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ์–ด๋Š ์ •๋„ ๊ฐ€๋…์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์žฌ์‚ฌ์šฉ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

๋ณด๋‹ค ๊ตฌ์ฒด์ ์œผ๋กœ ๋‹ค์Œ์„ ์ถ”์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

Property(
  initState: (_) => fetchUser(widget.userId),
  didUpdateWidget: (oldWidget) {
    if (oldWidget.userId != widget.userId)
      return fetchUser(widget.userId);
  }
)

_ExampleState ์—์„œ ๋…ผ๋ฆฌ๊ฐ€ Example ๋ฐ initState + didUpdateWidget ๋ฐ”์ธ๋”ฉ๋˜๋ฏ€๋กœ ๋‹ค๋ฅธ ์œ„์ ฏ์—์„œ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

Rust ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๋น„์Šทํ•œ ๊ฒƒ์„ ๋ณธ ํ›„ @timsneath์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋‹จ ์ฝ”์–ด์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ถ”์ถœํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. BLoC ํŒจํ„ด์€ provider๊ฐ€ ๋‚˜์˜ค๊ธฐ ์ „์— ์ง€์ •๋˜์—ˆ์ง€๋งŒ ์ง€๊ธˆ์€ provider๊ฐ€ ๊ถŒ์žฅ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค. ์•„๋งˆ๋„ flutter_hooks๋Š” ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ "์ถ•๋ณต๋ฐ›์€" ๋ฒ„์ „์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฏธ๋ž˜์— ์‚ฌ๋žŒ๋“ค์ด ์ƒ๊ฐํ•ด ๋‚ธ ํ›„ํฌ์— ๋Œ€ํ•œ ๊ฐœ์„  ์‚ฌํ•ญ์ด ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ง์„ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ œ ํ›„ํฌ๊ฐ€ ์žˆ๋Š” React๋Š” ์‹ค์ œ๋กœ ํ›„ํฌ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ๋น ์ ธ ๋‚˜์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์€ ํ•ต์‹ฌ์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณธ์งˆ์ ์œผ๋กœ ์˜์›ํžˆ ํด๋ž˜์Šค ๊ตฌ์„ฑ ์š”์†Œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ด๋ฅผ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‚˜๋Š” ํŒจํ‚ค์ง€ ์ฒ ํ•™์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ์ฑ„ํƒ๋ฅ ์ด ๋‚ฎ๊ณ  ์‚ฌ๋žŒ๋“ค์ด ์ž์‹ ์—๊ฒŒ ๋งž๋Š” ๊ฒƒ์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์—๊ฒŒ flutter_hooks๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ถŒ์žฅํ•˜๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๊ณต๊ธ‰์ž๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์ด ์–ผ๋งˆ๋‚˜ ๋งŽ์€์ง€ ์œ ์‚ฌํ•˜๊ฒŒ ์‚ดํŽด๋ณด๋ฉด ํฐ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋˜ํ•œ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•˜๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ผ์ดํ”„ ์‚ฌ์ดํด ๋กœ์ง์— ๋Œ€ํ•œ ์šฐ์ˆ˜ํ•œ ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ์™€ "๋ฌธ์ œ์ "์„ ๊ฒฝํ—˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

React/flutter_hooks์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class FetchUser extends Hook<AsyncSnapshot<User>> {
  const FetchUser(this.userId);
  final int userId;

  <strong i="8">@override</strong>
  _FetchUserState createState() => _FetchUserState();
}

class _FetchUserState extends HookState<AsyncSnapshot<User>, FetchUser> {
  Future<User> userFuture;

  <strong i="9">@override</strong>
  void initHook() {
    userFuture = fetchUser(hook.userId);
  }  

  void didUpdateHook(FetchUser oldHook) {
    if (oldHook.userId != hook.userId)
      userFuture = fetchUser(hook.userId);
  }


  <strong i="10">@override</strong>
  User build() {
    return useFuture(userFuture);
  }
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ์‚ฌ์šฉ:

class Example extends HookWidget {
  const Example({Key key, this.userId}) : super(key: key);

  final int userId;

  <strong i="14">@override</strong>
  Widget build(BuildContext context) {
    AsyncSnapshot<User> user = use(FetchUser(userId));

    if (!user.hasData)
      return CircularProgressIndicator();
    return Text(user.data.name);
  }
}

์ด ์ƒํ™ฉ์—์„œ ๋…ผ๋ฆฌ๋Š” Example ๋ฐ StatefulWidget ์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ์™€ ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ž…๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ userId ๋‹ค๋ฅด๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ๋‹ค๋ฅธ ์œ„์ ฏ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด์ฉŒ๋ฉด ๋‹ค๋ฅธ ์œ„์ ฏ์ด ๋  ๊ฒƒ์ด๋ผ๋Š” StatefulWidget ์˜ ๊ด€๋ฆฌํ•˜๋Š” userId ๋‚ด๋ถ€์ ์œผ๋กœ. ๋Œ€์‹  InheritedWidget์—์„œ userId ๋ฅผ ์–ป์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ตฌ๋ฌธ์€ ํ›„ํฌ๊ฐ€ ์ž์ฒด ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง„ ๋…๋ฆฝ์ ์ธ State ๊ฐœ์ฒด์™€ ๊ฐ™๋‹ค๋Š” ๊ฒƒ์„ ๋ถ„๋ช…ํžˆ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ํŒจํ‚ค์ง€ ์šฐ์„  ์ ‘๊ทผ ๋ฐฉ์‹์˜ ํ•œ ๊ฐ€์ง€ ๋‹จ์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํŒจํ‚ค์ง€ ์ž‘์„ฑ์ž๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ์— ์˜์กดํ•˜๋Š” ํŒจํ‚ค์ง€๋ฅผ ๊ฒŒ์‹œํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์ ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, Provider ์‚ฌ์šฉ์ž๊ฐ€ ์ง๋ฉดํ•œ ํ•œ ๊ฐ€์ง€ ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ๋•Œ ํ•ด๋‹น ์ƒํƒœ๋ฅผ ์ž๋™์œผ๋กœ ํ๊ธฐํ•˜๋ ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋ฌธ์ œ๋Š” Provider ์‚ฌ์šฉ์ž๊ฐ€ ์žฅํ™ฉํ•œ Consumer(builder: ...) / Selector(builder:...) ๊ตฌ๋ฌธ๊ณผ ๋‹ฌ๋ฆฌ context.watch / context.select ๊ตฌ๋ฌธ๋„ ์ƒ๋‹นํžˆ ์ข‹์•„ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์ด ๋ฉ‹์ง„ ๊ตฌ๋ฌธ์„ _๊ทธ๋ฆฌ๊ณ _ ํ›„ํฌ ์—†์ด ์ด์ „์— ์–ธ๊ธ‰ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(๋˜๋Š” ๊ฑฐ๋ถ€๋œ https://github.com/flutter/flutter/pull/33213).

๋ฌธ์ œ๋Š”:
๊ณต๊ธ‰์ž๋Š” ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด flutter_hooks ์— ์˜์กดํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
Provider์˜ ์ธ๊ธฐ ๋•Œ๋ฌธ์— ํ›„ํฌ์— ์˜์กดํ•˜๋Š” ๊ฒƒ์€ ๋น„ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๊ฒฐ๊ตญ ๋‹ค์Œ์„ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๋ถ„๊ธฐ ๊ณต๊ธ‰์ž( Riverpod ์˜ ์ฝ”๋“œ๋ช…์œผ๋กœ)
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ "Flutter ์ฆ๊ฒจ์ฐพ๊ธฐ"/Google ์ถ”์ฒœ์„ ์ž๋ฐœ์ ์œผ๋กœ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์‹ญ์‹œ์˜ค.
  • context.watch ๋ฅผ ์ฆ๊ธฐ๋Š” ์‚ฌ๋žŒ๋“ค์ด ์›ํ•˜๋Š” ๊ตฌ๋ฌธ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ์— ๋Œ€ํ•œ ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์ด Provider์— ๋น„ํ•ด ์ƒ๋‹นํ•œ ๊ฐœ์„ ์„ ๊ฐ€์ ธ์˜จ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด๊ฐ€ ์ƒ๊ฐํ•ด๋‚ธ ๊ฒƒ์— ์ƒ๋‹นํžˆ ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค(๊ทธ๊ฒƒ์€ InheritedWidgets๋ฅผ ์ปดํŒŒ์ผ ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค).
๊ทธ๋Ÿฌ๋‚˜ ๊ฑฐ๊ธฐ์— ๊ฐ€๋Š” ๊ธธ์€ ๋‚˜์—๊ฒŒ ๋‚˜์œ ๋’ท๋ง›์„ ๋‚จ๊ฒผ์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ ๋ฒ„์ „๊ณผ ์†์„ฑ ๋ฒ„์ „ ์‚ฌ์ด์—๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ธ ๊ฐ€์ง€ ์ฐจ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • Hooks ๋ฒ„์ „์€ ํ›จ์”ฌ ๋” ๋งŽ์€ ๋ฐฑ์—… ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
  • ์†์„ฑ ๋ฒ„์ „์€ ํ›จ์”ฌ ๋” ๋งŽ์€ ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
  • Hooks ๋ฒ„์ „์€ ์ž˜๋ชป๋œ ์ˆœ์„œ๋กœ ํ›„ํฌ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ƒํ™ฉ์ด ๋‚˜๋น ์ง€๊ณ  ์ฝ”๋“œ์—์„œ ์ฆ‰์‹œ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†๋Š” ๋นŒ๋“œ ๋ฉ”์„œ๋“œ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๊ฐ€ ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ํฐ ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ? ๋‚ด ๋ง์€, ์ด์ œ ์†์„ฑ์„ ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ๋ชจ๋‘ ํ•œ ๊ณณ์— ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ง€๊ธˆ์€ ์ •๋ง _์œ ์ผํ•œ_ ์žฅํ™ฉํ•œ ์ฃผ์žฅ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ข‹์€ ์†”๋ฃจ์…˜์ด ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์•Œ๊ณ  ์žˆ๋Š” ๋‹ค๋ฅธ ํŒจํ‚ค์ง€์— ์˜์กดํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ์— ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ๋“ค์€ ๋ฌธ์ œ๊ฐ€๋˜์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ๋ฌธ์ œ๋ผ๋ฉด IMHO๋Š” API์— ๋Œ€ํ•œ ์œ„ํ—˜ ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

๋‚ด ๋ง์€, ์ด์ œ ์†์„ฑ์„ ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ๋ชจ๋‘ ํ•œ ๊ณณ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ๊ฐ€ ํ•œ ๊ณณ์— ์žˆ๋‹ค๊ณ  ํ•ด์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.
ํ˜„์žฌ _ExampleState ๋‚ด๋ถ€์— ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ์œ„์ ฏ์—์„œ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ณด์กฐ ์œ„์ ฏ์„ ๋งŒ๋“ค์–ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?
๋น„ํ‹€๊ธฐ: ์ƒˆ ์œ„์ ฏ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด State ๋‚ด๋ถ€์—์„œ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ์ž ID๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class _WhateverState extends State with PropertyManager {
  // may change over time after some setState calls
  int userId;
}

์‚ฌ๋žŒ๋“ค์ด ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ๋ฌธ์ œ๋ผ๋ฉด IMHO๋Š” API์— ๋Œ€ํ•œ ์œ„ํ—˜ ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

๊ณต์‹์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•ด์„œ API๊ฐ€ ๋‚˜์˜๋‹ค๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

(๋ฒ„์ „ ๊ด€๋ฆฌ, ๋ผ์ด์„ ์Šค, ๊ฐ๊ฐ€์ƒ๊ฐ ๋ฐ ๊ธฐํƒ€ ์‚ฌํ•ญ์œผ๋กœ ์ธํ•ด) ์œ ์ง€ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ถ”๊ฐ€ ์ž‘์—…์ด๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€ ์™„์ „ํžˆ ํ•ฉ๋ฒ•์ ์ž…๋‹ˆ๋‹ค.
๋‚ด๊ฐ€ ๊ธฐ์–ตํ•˜๋Š” ๋ฐ”์— ๋”ฐ๋ฅด๋ฉด Flutter์—๋Š” ๊ฐ€๋Šฅํ•œ ํ•œ ์ ์€ ์ข…์†์„ฑ์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ์š”๊ตฌ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋„๋ฆฌ ๋ฐ›์•„๋“ค์—ฌ์ง€๊ณ  ๊ฑฐ์˜ ๊ณต์‹ํ™”๋œ Provider ์ž์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ "๋‚˜๋Š” ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด์žฅ๋œ InheritedWidgets๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ _ExampleState ๋‚ด๋ถ€์— ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ์œ„์ ฏ์—์„œ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ณด์กฐ ์œ„์ ฏ์„ ๋งŒ๋“ค์–ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๋ฌธ์ œ์˜ ์ฝ”๋“œ๋Š” ์œ„์ ฏ์—์„œ userId๋ฅผ ๊ฐ€์ ธ์™€ fetchUser ๋ฉ”์†Œ๋“œ์— ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋™์ผํ•œ ๊ฐ์ฒด์—์„œ ๋กœ์ปฌ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” userId๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ดœ์ฐฎ์€ ๊ฒƒ ๊ฐ™์ฃ ? ์—ฌ๊ธฐ์„œ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ก์„ ์œ„ํ•ด ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค๋ช…ํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

class Example extends StatefulWidget {
  Example({ Key key }): super(key: key);

  <strong i="10">@override</strong>
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> with PropertyManager {
  int _userId;
  Future<User> _future;

  void _setUserId(int newId) {
    if (newId == _userId)
      return;
    setState(() {
      _future = fetchUser(_userId);
    });
  }

  // ...code that uses _setUserId...

  <strong i="11">@override</strong>
  Widget build(BuildContext context) {
    return FutureBuilder<User>(
      future: _future.value,
      builder: (context, snapshot) {
        if (!snapshot.hasData) return Text('loading');
        return Text(snapshot.data.name);
      },
    );
  }
}

๊ณต์‹์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•ด์„œ API๊ฐ€ ๋‚˜์˜๋‹ค๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

๋™์˜.

์‚ฌ๋žŒ๋“ค์ด ๋‚˜์œ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์€ API๊ฐ€ ๋‚˜์˜๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. "ํŒจํ‚ค์ง€ ์ž‘์„ฑ์ž๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ์— ์˜์กดํ•˜๋Š” ํŒจํ‚ค์ง€๋ฅผ ๊ฒŒ์‹œํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์ ์Šต๋‹ˆ๋‹ค."๋ผ๊ณ  ๋งํ•˜๋ฉด ํ›„ํฌ๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์œ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์— ์˜์กดํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ข‹์€ API์ธ IMHO๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์ฑ„ํƒํ•˜๋”๋ผ๋„ ๋‚˜์˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์•Œ์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์œ ์ง€๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์œ„์˜ Property ์˜ˆ์ œ๋Š” ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ํŒจํ‚ค์ง€์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ๊ทธ ์ž์ฒด๋กœ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋„๋ฆฌ ๋ฐ›์•„๋“ค์—ฌ์ง€๊ณ  ๊ฑฐ์˜ ๊ณต์‹ํ™”๋œ Provider ์ž์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ "๋‚˜๋Š” ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด์žฅ๋œ InheritedWidgets๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

InheritedWidget์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ๋ฌธ์ œ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ํ•ด๊ฒฐ์ฑ…์„ ๊ฐ•์š”ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ๊ทธ๋“ค์ด ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๋ง ๊ทธ๋Œ€๋กœ ๋ฌธ์ œ๊ฐ€ ์—†๋Š” ๊ฒƒ์„ ์„ค๋ช…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. InheritedWidget ์‚ฌ์šฉ์„ ์„ ํ˜ธํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์€ ๋ฐฉํ•ด๊ฐ€ ๋˜์ง€ ์•Š๊ณ  InheritedWidget์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

. ์ข‹์€ API์ธ IMHO๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์ฑ„ํƒํ•˜๋”๋ผ๋„ ๋‚˜์˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์•Œ์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์œ ์ง€๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์œ„์˜ Property ์˜ˆ์ œ๋Š” ์ž์ฒด์ ์œผ๋กœ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ํŒจํ‚ค์ง€์— ์˜์กดํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜คํ•ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ๋“ค์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.
ํ›„ํฌ๋Š” ๊ณต์‹์ ์ด์ง€ ์•Š์ง€๋งŒ Provider๋Š” ๊ณต์‹์ด๊ธฐ ๋•Œ๋ฌธ์— Provider๊ฐ€ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๋™์ผํ•œ ๊ฐ์ฒด์—์„œ ๋กœ์ปฌ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” userId๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ดœ์ฐฎ์€ ๊ฒƒ ๊ฐ™์ฃ ? ์—ฌ๊ธฐ์„œ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ก์„ ์œ„ํ•ด ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค๋ช…ํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ›„ํฌ์™€ ์†์„ฑ ๊ฐ„์˜ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด ํŠน๋ณ„ํžˆ ์š”์ฒญํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด FetchUser ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class _WhateverState extends State with PropertyManager {
  // may change over time after some setState calls
  int userId;

  Widget build(context) {
    final user = use(FetchUser(userId));
  }
}

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด FetchUser ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒŒ ์™œ ๋ฐ”๋žŒ์งํ•œ์ง€ ์ดํ•ด๊ฐ€ ์•ˆ๋ฉ๋‹ˆ๋‹ค. FetchUser ์—๋Š” ํฅ๋ฏธ๋กœ์šด ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉฐ Hooks์—์„œ fetchUser ํ•จ์ˆ˜๋กœ์˜ ์–ด๋Œ‘ํ„ฐ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. fetchUser ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์žฌ์‚ฌ์šฉ ์ค‘์ธ ์ฝ”๋“œ๋Š” ํฅ๋ฏธ๋กœ์šด ์ฝ”๋“œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ๊ณต์‹์ ์ด์ง€ ์•Š์ง€๋งŒ Provider๋Š” ๊ณต์‹์ด๊ธฐ ๋•Œ๋ฌธ์— Provider๊ฐ€ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ฌธ์ œ์— ๋Œ€ํ•œ IMHO์˜ ์ข‹์€ ์†”๋ฃจ์…˜์€ ๊ณต๊ธ‰์ž๊ฐ€ ์ „ํ˜€ ์ฑ„ํƒํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์€ ์™„์ „ํžˆ ์ง๊ตํ•˜๋Š” ๊ฐœ๋…์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Flutter ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ๊ฐ€ "์™„๋ฃŒ๋ฅผ ํ”ผํ•˜์‹ญ์‹œ์˜ค"๋ผ๋Š” ์ œ๋ชฉ์œผ๋กœ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒŒ ์™œ ๋ฐ”๋žŒ์งํ•œ์ง€ ์ดํ•ด๊ฐ€ ์•ˆ๋ฉ๋‹ˆ๋‹ค. FetchUser์—๋Š” ํฅ๋ฏธ๋กœ์šด ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉฐ Hooks์—์„œ fetchUser ํ•จ์ˆ˜๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ์–ด๋Œ‘ํ„ฐ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. fetchUser๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์žฌ์‚ฌ์šฉ ์ค‘์ธ ์ฝ”๋“œ๋Š” ํฅ๋ฏธ๋กœ์šด ์ฝ”๋“œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋ณด์—ฌ์ฃผ๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. fetchUser ๋Š” ๋ฌด์—‡์ด๋“  ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ ChangeNotifier.addListener .

fetchUser ์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ๋Œ€์ฒด ๊ตฌํ˜„์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹จ์ˆœํžˆ ์•”์‹œ์  ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” API๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

int userId;

Widget build(context) {
  AsyncSnapshot<User> user = use(ImplicitFetcher<User>(userId, fetch: () => fetchUser(userId));
}

์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ฌธ์ œ์— ๋Œ€ํ•œ IMHO์˜ ์ข‹์€ ์†”๋ฃจ์…˜์€ ๊ณต๊ธ‰์ž๊ฐ€ ์ „ํ˜€ ์ฑ„ํƒํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์€ ์™„์ „ํžˆ ์ง๊ตํ•˜๋Š” ๊ฐœ๋…์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Flutter ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ๊ฐ€ "์™„๋ฃŒ๋ฅผ ํ”ผํ•˜์‹ญ์‹œ์˜ค"๋ผ๋Š” ์ œ๋ชฉ์œผ๋กœ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ํ›„ํฌ๊ฐ€ ์›์‹œ์ ์ด๋ผ๊ณ  ์–ธ๊ธ‰ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.

์€์œ ๋กœ:
package:animations ๋Š” Animation ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด ํ•ต์‹ฌ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
package:animations ๊ฐ€ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์œ ์ง€ ๊ด€๋ฆฌํ•˜๋Š” Animation ์˜ ํฌํฌ๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@escamoteur ๊ทธ๋ƒฅ ์ดํ•ดํ•˜๋Š”๋ฐ, ์œ„์ ฏ์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์„ ๊ทผ๋ณธ์ ์œผ๋กœ

@Hixie ์ œ ์š”์ ์€ ํ›„ํฌ๊ฐ€ ๋” ์œ ๋ช…
๋‚˜๋Š” ๋‹น์‹ ์˜ ์šฐ๋ ค๋ฅผ ๋งค์šฐ ๋งŽ์ด ๊ณต์œ ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ํ•œํŽธ์œผ๋กœ๋Š” ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ์œ„์ ฏ์ด ์ •๋ง ์šฐ์•„ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.
์ด์ „๊ณผ ๊ฐ™์€ ์ผ์„ ํ•˜๋Š” ๊ฒƒ์„ ๊ธˆ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด์ „๊ณผ ๊ฐ™์€ ์ผ์„ ํ•˜๋Š” ๊ฒƒ์„ ๊ธˆ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Flutter ํŒ€์ด "์ด์ œ ์šฐ๋ฆฌ๋Š” flutter hooks๋ฅผ ๊ถŒ์žฅํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ์ด์ „์ฒ˜๋Ÿผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ์ƒ๊ฐ์ด ์•„๋‹ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด ์ด๊ฒƒ์— ๋Œ€ํ•ด ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ Flutter ํŒ€์ด ํ–ฅํ›„ ํ›„ํฌ๋ฅผ ๊ถŒ์žฅํ•œ๋‹ค๋ฉด ์‹ค์ œ Flutter ์ฝ”๋“œ๋ฅผ ์˜ˆ์ œ๋กœ ๊ฒŒ์‹œํ•˜๋Š” ๊ฒƒ์„ ์ค‘๋‹จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ๋žŒ๋“ค์€ ํ•ญ์ƒ "๊ณต์‹์ ์ธ ๋ฐฉ๋ฒ•"์„ ๋”ฐ๋ฅด๊ณ  Flutter๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ๊ณต์‹์ ์ธ ๋ฐฉ๋ฒ•์ด ์žˆ์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋ณด์—ฌ์ฃผ๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. fetchUser ๋Š” ๋ฌด์—‡์ด๋“  ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ ChangeNotifier.addListener .

ํ™•์‹ ํ•˜๋Š”. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ํ•จ์ˆ˜๊ฐ€ ์ข‹์€ ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ์ถ”์ƒํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ์†์„ฑ ์ฝ”๋“œ์™€ ์œ„์˜ _setUserId ์ฝ”๋“œ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํŠน๋ณ„ํ•œ ๋„์›€ ์—†์ด ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ํ˜ธ์ถœํ•˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ํ•œ ๊ณณ์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํ˜ธ์ถœ์„ ๋ž˜ํ•‘ํ•˜๊ธฐ ์œ„ํ•ด Hook์ด ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ฌธ์ œ์— ๋Œ€ํ•œ IMHO์˜ ์ข‹์€ ์†”๋ฃจ์…˜์€ ๊ณต๊ธ‰์ž๊ฐ€ ์ „ํ˜€ ์ฑ„ํƒํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์€ ์™„์ „ํžˆ ์ง๊ตํ•˜๋Š” ๊ฐœ๋…์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Flutter ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ๊ฐ€ "์™„๋ฃŒ๋ฅผ ํ”ผํ•˜์‹ญ์‹œ์˜ค"๋ผ๋Š” ์ œ๋ชฉ์œผ๋กœ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ํ›„ํฌ๊ฐ€ ์›์‹œ์ ์ด๋ผ๊ณ  ์–ธ๊ธ‰ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ๋“ค์€ ํŽธ๋ฆฌํ•จ์ด๋ฉฐ ์›์‹œ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์ด ์›์‹œ์ ์ด๋ผ๋ฉด "๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?"๋ผ๋Š” ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜๊ธฐ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์€ "์—ฌ๊ธฐ ๋‚ด๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ์ผ์ด ์žˆ๋Š”๋ฐ ํ•  ์ˆ˜ ์—†๋‹ค"๊ณ  ๋งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์€์œ ๋กœ:
package:animations ๋Š” Animation ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด ํ•ต์‹ฌ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
package:animations ๊ฐ€ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์œ ์ง€ ๊ด€๋ฆฌํ•˜๋Š” Animation ์˜ ํฌํฌ๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Animation ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ๋Š” ๊ธฐ๋ณธ์ ์ธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ํ‹ฐ์ปค์™€ ์ด๋ฅผ ์ œ์–ดํ•˜๊ณ  ๊ตฌ๋…ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. Animation ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ๊ฐ€ ์—†์œผ๋ฉด ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด Animation ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ์™€ ๊ฐ™์€ ๊ฒƒ์„ ๋ฐœ๋ช…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. (์ด์ƒ์ ์œผ๋กœ๋Š” ๋” ๋‚˜์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ์ตœ์„ ์€ ์•„๋‹™๋‹ˆ๋‹ค.) Hooks๋Š” ์ƒˆ๋กœ์šด ๊ธฐ๋ณธ ๊ธฐ๋Šฅ์„ ๋„์ž…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ๋” ๊ฐ„๋‹จํ•˜๊ฑฐ๋‚˜ ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ์™€ ๋‹ค๋ฅด๊ฒŒ ์ธ์ˆ˜๋ถ„ํ•ด๋  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ธฐ๋ณธ ์š”์†Œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. Hooks๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์™€ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด Hooks์™€ ์œ ์‚ฌํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ๋ฌธ์ œ์— ์„ค๋ช…๋œ ๋ฌธ์ œ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ˆ˜์ •ํ•ด์•ผ ํ•  ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค๋งˆ๋‹ค ๊ทธ๊ฒƒ์„ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์ด ๋งค์šฐ ๋‹ค๋ฅผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ณ ์น  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฒ„๊ทธ์—์„œ ์ด๋ฏธ ๋ช‡ ๊ฐ€์ง€๋ฅผ ๋…ผ์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ณ  ๋ช‡ ๋ถ„ ์•ˆ์— ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์†”๋ฃจ์…˜์„ ์†Œ์œ ํ•˜๊ณ  ์œ ์ง€ํ•˜๋Š” ๋ฐ ๊ฐ€์น˜๋ฅผ ์ œ๊ณตํ•  ์ •๋„๋กœ ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ค์šด ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ฐ ์ œ์•ˆ์—๋Š” ๊ฐ•์ ๊ณผ ์•ฝ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์•ฝ์ ์€ ๊ฐ๊ฐ์˜ ๊ฒฝ์šฐ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์•ฝ์ ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉํ•ดํ•˜๋Š” ์š”์†Œ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์‚ฌ๋žŒ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜๋Š”์ง€์กฐ์ฐจ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ _are_ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ
๋‹ค์Œ์€ Dan์˜ ์Šค๋ ˆ๋“œ์ž…๋‹ˆ๋‹ค. https://twitter.com/dan_abramov/status/1093698629708251136 ์ด์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ถ€ ํ‘œํ˜„์€ ๋‹ค๋ฅด์ง€๋งŒ React ํด๋ž˜์Šค Components์™€ Flutter StatefulWidgets ๊ฐ„์˜ ์œ ์‚ฌ์„ฑ์œผ๋กœ ์ธํ•ด ๋…ผ๋ฆฌ๋Š” ๋Œ€๋ถ€๋ถ„ Flutter์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋” ๊ตฌ์ฒด์ ์œผ๋กœ ๋งํ•˜๋ฉด flutter_hooks ๋ฅผ ๋™์  ์ƒํƒœ ๋ฏน์Šค์ธ์œผ๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋“ค์ด ์›์‹œ์ ์ด๋ผ๋ฉด "๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?"๋ผ๋Š” ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜๊ธฐ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์€ "์—ฌ๊ธฐ ๋‚ด๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ์ผ์ด ์žˆ๋Š”๋ฐ ํ•  ์ˆ˜ ์—†๋‹ค"๊ณ  ๋งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

OP์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋ณต์žกํ•˜๊ณ  ๊นŠ์ด ์ค‘์ฒฉ๋œ ๋นŒ๋“œ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์—ฌ๋Ÿฌ ์œ„์ ฏ์— ๋…ผ๋ฆฌ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๋ฏน์Šค์ธ์ด๋‚˜ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ๊ฐ€ ๋” ๊ฐ„๋‹จํ•˜๊ฑฐ๋‚˜ ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ์™€ ๋‹ค๋ฅด๊ฒŒ ์ธ์ˆ˜๋ถ„ํ•ด๋  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ธฐ๋ณธ ์š”์†Œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. Hooks๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์™€ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด Hooks์™€ ์œ ์‚ฌํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๊ตฌ์กฐํ™”ํ•˜๊ณ  ์˜๋ฏธ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ธ์ˆ˜๋ถ„ํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ํด๋ž˜์Šค๋Š” ๊ธฐ๋ณธ ์š”์†Œ์ž…๋‹ˆ๋‹ค.

ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ์ธ ๋ฏน์Šค์ธ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ๊ฐ™์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํ˜ธ์ถœ์„ ๋ž˜ํ•‘ํ•˜๊ธฐ ์œ„ํ•ด Hook์ด ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์šฐ๋ฆฌ๊ฐ€ ์ด ๋…ผ๋ฆฌ๋ฅผ _one_ ์žฅ์†Œ๊ฐ€ ์•„๋‹ˆ๋ผ _two_ ์žฅ์†Œ์—์„œ ํ˜ธ์ถœํ•ด์•ผ ํ•  ๋•Œ๋ฅผ ์œ„ํ•ด.

๋ฏน์Šค์ธ์ด๋‚˜ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ค ๊ฒฝ์šฐ์ธ์ง€ ๊ตฌ์ฒด์ ์ธ ์˜ˆ๋ฅผ ๋“ค์–ด์ฃผ์„ธ์š”. ์ง€๊ธˆ๊นŒ์ง€ ์šฐ๋ฆฌ๊ฐ€ ์—ฐ๊ตฌํ•œ ๋ชจ๋“  ์˜ˆ์ œ๋Š” ํ›„ํฌ ์—†์ด ๊ฐ„๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์ด ์Šค๋ ˆ๋“œ์—์„œ @rrousselGit ํ›„ํฌ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•˜๊ณ  ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์„ ๋ณธ ์ ์ด ์—†์Šต๋‹ˆ๋‹ค.

์ตœ๊ทผ์— ๋‹คํŠธ์™€ ํ”Œ๋Ÿฌํ„ฐ๋ฅผ ๋งŽ์ด ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์œ„์˜ ์†์„ฑ ์†”๋ฃจ์…˜ ์ฝ”๋“œ ์ƒ˜ํ”Œ์—์„œ ๋ˆ„๋ฝ๋œ ํ•ญ๋ชฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์˜ค๋Š˜๋‚  ์žฌ์‚ฌ์šฉ ๋Œ€์‹  ๋ณต์‚ฌ ๋ถ™์—ฌ๋„ฃ๊ธฐ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ์˜ต์…˜์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
@rrousselGit ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋Œ€๋‹ต์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

ํ˜„์žฌ _ExampleState ๋‚ด๋ถ€์— ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ์œ„์ ฏ์—์„œ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ณด์กฐ ์œ„์ ฏ์„ ๋งŒ๋“ค์–ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?
ํŠธ์œ„์ŠคํŠธ: ์ƒˆ ์œ„์ ฏ์€ State ๋‚ด๋ถ€์—์„œ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ์ž ID๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์†์„ฑ ์†”๋ฃจ์…˜์œผ๋กœ ์‰ฌ์šด ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ๋‹ค๋ฅธ ์˜ต์…˜์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
๋‹ต์€ ๋‹จ์ˆœํžˆ ํ”Œ๋Ÿฌํ„ฐ์—์„œ ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๊นŒ? ์™„์ „ํžˆ ๊ดœ์ฐฎ์ง€ ๋งŒ ์•ฝ๊ฐ„ ์Šฌํ”ˆ IMHO.

BTW, SwiftUI๊ฐ€ ์ƒˆ๋กญ๊ณ /๋‹ค๋ฅธ ์˜๊ฐ์„ ์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ๋™์ผํ•œ ์ƒํƒœ ๋…ผ๋ฆฌ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ์„ฑ๋„ ๋ถ€์กฑํ•ฉ๋‹ˆ๊นŒ? ๋‚˜๋Š” swiftui๋ฅผ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์–ด์ฉŒ๋ฉด ๋„ˆ๋ฌด ๋‹ค๋ฅธ๊ฐ€์š”?

๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ๋นŒ๋”. ๋นŒ๋”๋Š” ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
Hooks๋Š” ๋นŒ๋”๋ฅผ ๋” ์ฝ๊ธฐ ์‰ฝ๊ณ  ์ƒ์„ฑํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.


๋‹ค์Œ์€ ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ๋ฅผ ์œ„ํ•ด ์ง€๋‚œ๋‹ฌ์— ๋งŒ๋“  ์‚ฌ์šฉ์ž ์ •์˜ ํ›„ํฌ ๋ชจ์Œ์ž…๋‹ˆ๋‹ค.

  • useQuery โ€“ ์ด์ „์— ์ œ๊ณตํ•œ ImplicitFetcher ํ›„ํฌ์™€ ๋™์ผํ•˜์ง€๋งŒ ๋Œ€์‹  GraphQL ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  • useOnResume ์ฝœ๋ฐฑ ์ œ๊ณต์— ์ง€์ • ๋™์ž‘ ์ˆ˜ํ–‰ AppLifecycleState.resumed ์•Š๊ณ ๋„
    WidgetsBindingObserver๋ฅผ ๋งŒ๋“œ๋Š” ๋ฌธ์ œ๋กœ ๊ฐ€์‹ญ์‹œ์˜ค.
  • useDebouncedListener ๋ฆฌ์Šค๋„ˆ๋ธ”(์ผ๋ฐ˜์ ์œผ๋กœ TextField ๋˜๋Š” ScrollController)์„ ์ˆ˜์‹ ํ•˜์ง€๋งŒ ๋ฆฌ์Šค๋„ˆ์—์„œ ๋””๋ฐ”์šด์Šค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • useAppLinkService ์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์ด ์žˆ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ์ด๋ฒคํŠธ์—์„œ ์œ„์ ฏ์ด ์ผ๋ถ€ ๋…ผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” AppLifecycleState.resumed
  • useShrinkUIForKeyboard ํ‚ค๋ณด๋“œ ๋ชจ์–‘์„ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. UI๊ฐ€ ํ•˜๋‹จ ํŒจ๋”ฉ์— ์ ์‘ํ•ด์•ผ ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ถ€์šธ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค(focusNode ์ˆ˜์‹ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•จ).
  • useFilter useDebouncedListener ๋ฐ useState (๋‹จ์ผ ์†์„ฑ์„ ์„ ์–ธํ•˜๋Š” ๊ธฐ๋ณธ ํ›„ํฌ)๋ฅผ ๊ฒฐํ•ฉํ•˜์—ฌ ๊ฒ€์ƒ‰ ์ฐฝ์— ๋Œ€ํ•œ ํ•„ํ„ฐ๋ฅผ ๋…ธ์ถœํ•˜๋Š”
  • useImplicitlyAnimated<Int/Double/Color/...> โ€“ TweenAnimationBuilder ํ›„ํฌ์™€ ๋™์ผ

์•ฑ์€ ๋˜ํ•œ ๋‹ค์–‘ํ•œ ๋…ผ๋ฆฌ์— ๋Œ€ํ•ด ๋งŽ์€ ์ €์ˆ˜์ค€ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ๋Œ€์‹ :

Whatever whatever;

initState() {
  whatever = doSomething(widget.id);
}

didUpdateWidget(oldWidget) {
  if (oldWidget.id != widget.id)
    whatever = doSomething(widget.id);
}

๊ทธ๋“ค์ดํ•˜๋‹ค:

Widget build(context) {
  final whatever = useUnaryEvent<Whatever, int>(widget.id, (int id) => doSomething(id));
}

์ด๊ฒƒ์€ initState / didUpdateWidget / didChangeDependencies ์‚ฌ์ด์˜ ์ค‘๋ณต์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋“ค์€ ๋˜ํ•œ StreamBuilder / ValueListenableBuilder ์ด์–ด์•ผ ํ•˜๋Š” useProvider ๋งŽ์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.


์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ ์œ„์ ฏ์ด "๋‹จ ํ•˜๋‚˜์˜ ํ›„ํฌ"๋ฅผ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด ์œ„์ ฏ์€ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class ChatScreen extends HookWidget {
  const ChatScreen({Key key}) : super(key: key);

  <strong i="13">@override</strong>
  Widget build(BuildContext context) {
    final filter = useFilter(debounceDuration: const Duration(seconds: 2));
    final userId = useProvider(authProvider).userId;
    final chatId = useProvider(selectedChatProvider);
    final chat = useQuery(ChatQuery(userId: userId, chatId: chatId, filter: filter.value));

    return Column(
      children: [
        Searchbar(onChanged: (value) => filter.value = value),
        Expanded(
          child: ChatList(chat: chat),
        ),
      ],
    );
  }
}

๊ฐ„๊ฒฐํ•˜๊ณ  ๋งค์šฐ ์ฝ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค(๋ฌผ๋ก  API์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ง€์‹์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •).
๋ชจ๋“  ๋…ผ๋ฆฌ๋Š” ์œ„์—์„œ ์•„๋ž˜๋กœ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”์„œ๋“œ ๊ฐ„์— ์ ํ”„๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์— ์‚ฌ์šฉ๋œ ๋ชจ๋“  ํ›„ํฌ๋Š” ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ์—ฌ๋Ÿฌ ์œ„์น˜์—์„œ ์žฌ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ ์—†์ด ๋˜‘๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฉ๋‹ˆ๋‹ค.

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

  <strong i="20">@override</strong>
  _ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  String filter;
  Timer timer;

  <strong i="21">@override</strong>
  void dispose() {
    timer?.cancel();
    super.dispose();
  }

  <strong i="22">@override</strong>
  Widget build(BuildContext context) {
    return Consumer<Auth>(
      provider: authProvider,
      builder: (context, auth, child) {
        return Consumer<int>(
          provider: selectedChatProvider,
          builder: (context, chatId, child) {
            return GraphQLBuilder<Chat>(
              query: ChatQuery(
                userId: auth.userId,
                chatId: chatId,
                filter: filter.value,
              ),
              builder: (context, chat, child) {
                return Column(
                  children: [
                    Searchbar(
                      onChanged: (value) {
                        timer?.cancel();
                        timer = Timer(const Duration(seconds: 2), () {
                          filter = value;
                        });
                      },
                    ),
                    Expanded(
                      child: ChatList(chat: chat),
                    ),
                  ],
                );
              },
            );
          },
        );
      },
    );
  }
}

์ด๊ฒƒ์€ ๊ฐ€๋…์„ฑ์ด ํ˜„์ €ํžˆ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

  • 10๋‹จ๊ณ„์˜ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•„ํ„ฐ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด FilterBuilder ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ 12๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.
  • ํ•„ํ„ฐ ๋กœ์ง์€ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

    • ์‹ค์ˆ˜๋กœ timer ์ทจ์†Œํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • build ๋ฐฉ๋ฒ•์˜ ์ ˆ๋ฐ˜์€ ๋…์ž์—๊ฒŒ ์œ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Builders๋Š” ์ค‘์š”ํ•œ ๊ฒƒ์—์„œ ์šฐ๋ฆฌ๋ฅผ ์‚ฐ๋งŒํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ด„ํ˜ธ๊ฐ€ ์—†์–ด์„œ ์ฝ”๋“œ๊ฐ€ ์ปดํŒŒ์ผ๋˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ 5๋ถ„์„ ๋‚ญ๋น„ํ–ˆ์Šต๋‹ˆ๋‹ค.

flutter_hooks ์‚ฌ์šฉ์ž๋กœ์„œ ์ œ ์˜๊ฒฌ์„ ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์—๋Š” Flutter์— ๋งŒ์กฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๋Ÿฐ ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ๋ณด์ง€ ์•Š์•˜๋‹ค. ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ฝ๊ณ  ๊ทธ๊ฒƒ์— ๋Œ€ํ•œ YouTube ๋น„๋””์˜ค๋ฅผ ๋ณธ ํ›„์—๋„ ์—ฌ์ „ํžˆ ํ™•์‹ ์ด ์„œ์ง€ ์•Š์•˜๊ณ  ๋ฉ‹์žˆ์–ด ๋ณด์˜€์ง€๋งŒ ์‹ค์ œ๋กœ ๋™๊ธฐ๋ฅผ ๋ถ€์—ฌํ•˜๋ ค๋ฉด ๋ช‡ ๊ฐ€์ง€ ์—ฐ์Šต์ด๋‚˜ ์˜ˆ์ œ๊ฐ€ ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋‚˜๋Š” ๋ญ”๊ฐ€๋ฅผ ์•Œ์•„์ฐจ๋ ธ๋‹ค. ๋‚˜๋Š” ์–ด๋–ค ํฌ์ƒ์„ ์น˜๋ฅด๋”๋ผ๋„ ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์„ ํ”ผํ•˜๊ณ  ์žˆ์—ˆ๊ณ  ๋งŽ์€ ์ƒ์šฉ๊ตฌ์™€ ๊ด€๋ จ๋œ ๋‚ด์šฉ์ด ์žˆ์—ˆ๊ณ  ํด๋ž˜์Šค๋ฅผ ๊ฑด๋„ˆ๋›ฐ๋ฉด์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ฐพ์œผ๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ์ž„์‹œ ์ƒํƒœ์˜ ๋Œ€๋ถ€๋ถ„์„ ๋‚˜๋จธ์ง€ ์•ฑ ์ƒํƒœ์™€ ํ•จ๊ป˜ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์œผ๋กœ ์˜ฎ๊ฒผ๊ณ  ์ƒํƒœ ๋น„์ €์žฅ ์œ„์ ฏ๋งŒ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜,์ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ์ ์  ์ด์œ ๋กœ ์ธํ•ด ์‹ ๋ขฐ์˜ ์‹ ์† ๋–จ๋ฆผ์— ๋”ฐ๋ผ ์›์ธ์ด Navigator , ๋˜๋Š” BuildContext ์— ์•ก์„ธ์Šคํ•˜๊ธฐ์œ„ํ•œ InheritedWidget ์˜ / Providers ๋†’์€ ๋‚˜๋ฌด. ๊ทธ๊ฒƒ์ด ์ข‹์€ ์ƒํƒœ ๊ด€๋ฆฌ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๊ณ  ๋งํ•˜์ง€๋Š” ์•Š์•˜์ง€๋งŒ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ UI์—์„œ ์ƒํƒœ ๊ด€๋ฆฌ์— ๋Œ€ํ•œ ๊ฑฑ์ •์„ ํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ž ์‹œ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•œ ํ›„ Flutter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ฑ ์ƒํƒœ๋ณด๋‹ค ์ž„์‹œ ์ƒํƒœ๋ฅผ ์ ์ ˆํ•œ ์œ„์น˜์—(UI์™€ ํ•จ๊ป˜) ํ›จ์”ฌ ๋” ์ƒ์‚ฐ์ ์ด๊ณ  ํ›จ์”ฌ ๋” ๋งŒ์กฑ์Šค๋Ÿฝ๊ฒŒ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜์—๊ฒŒ ๊ทธ๊ฒƒ์€ ์ž„์‹œ ์ƒํƒœ/์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์œ„ํ•œ ๊ฐ€๋น„์ง€ ์ˆ˜์ง‘๊ธฐ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. UI์—์„œ ๋ชจ๋“  ๊ตฌ๋…์„ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ ์ด๊ฒƒ์ด flutter_hooks ๊ฐ€ ์ €์—๊ฒŒ ํ•˜๋Š” ์ผ์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ์—ฌ์ „ํžˆ ์ž˜ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋‚ด ์ฝ”๋“œ๋ฅผ ์œ ์ง€ ๊ด€๋ฆฌํ•˜๊ณ  ๋ฆฌํŒฉํ† ๋งํ•˜๊ธฐ๊ฐ€ ํ›จ์”ฌ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ง€๋‚œ 1๋…„ ๋™์•ˆ ๋Œ€ํ•™์› ์—ฐ๊ตฌ์™€ ์žฌ๋ฏธ๋ฅผ ์œ„ํ•ด ~10๊ฐœ์˜ ์•ฑ์„ ์ž‘์„ฑํ•˜๋ฉด์„œ ์ด์•ผ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Flutter SDK ์ž์ฒด์— ํฌํ•จํ•ด์•ผ ํ•˜๋Š” ์ฃผ๋œ ๋™๊ธฐ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ •ํ™•ํžˆ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์— ๊ทธ ์ฃผ์ œ์— ๋Œ€ํ•ด ๋‘ ๊ฐ€์ง€ ์ƒ๊ฐ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๊ฐ€๋” ์ดˆ๊ธฐํ™”/ํ๊ธฐํ•ด์•ผ ํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์žˆ๋Š” ํŒจํ‚ค์ง€๋ฅผ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ›„ํฌ๋ฅผ ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค. (์˜ˆ: golden_layout ๋˜๋Š” zefyr ). ๋‚˜๋Š” flutter_hooks ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋“ค์ด ๊ทธ๋Ÿฌํ•œ ํŒจํ‚ค์ง€๋กœ๋ถ€ํ„ฐ ํ˜œํƒ์„ ๋ฐ›์„ ๊ฒƒ์ด๋ผ๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ง ๊ทธ๋Œ€๋กœ 1-3๊ฐœ์˜ ๊ธฐ๋Šฅ์„ ํฌํ•จํ•˜๋Š” ํŒจํ‚ค์ง€๋ฅผ ๊ฒŒ์‹œํ•˜๋Š” ๊ฒƒ์„ ์ •๋‹นํ™”ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋Œ€์•ˆ์€ ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค์–‘ํ•œ ํŒจํ‚ค์ง€์— ๋Œ€ํ•œ ๋งŽ์€ ํ›„ํฌ๋ฅผ ํฌํ•จํ•˜๋Š” ์ฃผ๋ฐฉ ์‹ฑํฌ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ git ์ข…์†์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ ํŒจํ‚ค์ง€ + flutter_hooks๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ์€ ๋‚ด git์— ์˜์กดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ˜œํƒ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด(๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ๊ณ  ๊ด€์‹ฌ ์—†๋Š” ํŒจํ‚ค์ง€์— ๋Œ€ํ•œ ์ข…์†์„ฑ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Œ) 3๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด ํฌํ•จ๋œ ํŒจํ‚ค์ง€ ๋˜๋Š” pub.dev์— garden-sink ํŒจํ‚ค์ง€๋ฅผ ๊ฒŒ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์•„์ด๋””์–ด๋Š” ์šฐ์Šค๊ฝ์Šค๋Ÿฝ๊ณ  ๋ฐœ๊ฒฌํ•˜๊ธฐ ์‰ฝ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. flutter_hooks ์˜ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋Š” ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ๋ณต์‚ฌํ•˜์—ฌ ์ฝ”๋“œ์— ๋ถ™์—ฌ๋„ฃ๊ฑฐ๋‚˜ ๋…ผ๋ฆฌ ์ž์ฒด๋ฅผ ํŒŒ์•…ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๋Š” ์ฝ”๋“œ/ํŒจํ‚ค์ง€๋ฅผ ๊ณต์œ ํ•˜๋Š” ์š”์ ์„ ์™„์ „ํžˆ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์€ ์ผ๋ถ€ 'ํ™•์žฅ ํŒจํ‚ค์ง€'๊ฐ€ ์•„๋‹Œ ์›๋ž˜ ํŒจํ‚ค์ง€๋กœ ๋“ค์–ด๊ฐ€๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ์ข‹์Šต๋‹ˆ๋‹ค. flutter_hooks ์ด ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€์ด๊ฑฐ๋‚˜ characters ์™€ ๊ฐ™์ด ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์‚ฌ์šฉ๋˜๊ฑฐ๋‚˜ ๋‚ด๋ณด๋‚ด์ง„ ํŒจํ‚ค์ง€์ธ ๊ฒฝ์šฐ ์›๋ž˜ ํŒจํ‚ค์ง€ ์ž‘์„ฑ์ž๋Š” ๊ฐ„๋‹จํ•œ ํ›„ํฌ์— ๋Œ€ํ•œ ํ’€ ์š”์ฒญ์„ ์ˆ˜๋ฝํ•  ๊ฐ€๋Šฅ์„ฑ์ด ํ›จ์”ฌ ๋” ๋†’์Šต๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์ด ์žˆ์œผ๋ฉฐ 1-3๊ฐœ์˜ ๊ธฐ๋Šฅ ํŒจํ‚ค์ง€๊ฐ€ ์—‰๋ง์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    flutter_hooks ๊ฐ€ Flutter์— ์˜ํ•ด ์ฑ„ํƒ๋˜์ง€ ์•Š์œผ๋ฉด pub.dev ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ์–ด์ง€๋Ÿฝํžˆ๋Š” 1-3๊ฐœ์˜ ํ•จ์ˆ˜ ํŒจํ‚ค์ง€๋ฅผ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด ํŒจํ‚ค์ง€๊ฐ€ ์ •๋ง ์ž‘๋‹ค๋Š” ์‚ฌ์‹ค์€ ์ด๊ฒƒ์ด ์›์‹œ์ ์ด๋ผ๋Š” @rrousselGit์— ์ •๋ง๋กœ ๋™์˜ํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. flutter_hooks ์ €์žฅ์†Œ ์— ์žˆ๋Š” 1228๊ฐœ์˜ ๋ณ„์ด @rrousselGit์—์„œ ์–ธ๊ธ‰ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค๋Š” ํ‘œ์‹œ๊ฐ€

  2. ๋‚ด๊ฐ€ ๋„์šธ ์ˆ˜ ์žˆ๋Š” ์ผ์— ๊ด€์‹ฌ์ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— Flutter ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ๊ธฐ์—ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ YouTube ๋™์˜์ƒ์„ ๋ณด๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ณด๊ณ  ์žˆ๋Š” ๋™์•ˆ ์ƒˆ ์†์„ฑ์— ๋น„๋””์˜ค๋ฅผ ๋งŒ๋“œ๋Š” ์‚ฌ๋žŒ์ด ์ƒ๋‹นํžˆ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€๋˜์—ˆ์ง€๋งŒ dispose , didUpdateWidget ๋ฐ debugFillProperties ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฑฐ์˜ ์žŠ์–ด ๋ฒ„๋ ธ์Šต๋‹ˆ๋‹ค. ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์˜ ๋ชจ๋“  ๋ณต์žก์„ฑ๊ณผ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋†“์น˜๋Š” ๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ์‰ฌ์šด์ง€ ๋‹ค์‹œ ๋ณด๋‹ˆ ๊ทธ๊ฒƒ๋“ค์„ ๋‹ค์‹œ ๋ถˆ์‹ ํ•˜๊ฒŒ ๋˜์—ˆ๊ณ  ๋ฉ”์ธ Flutter ์ €์žฅ์†Œ์— ๊ธฐ์—ฌํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ํฅ๋ถ„ํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋‚˜๋ฅผ ์™„์ „ํžˆ ๋‹จ๋…์‹œ์ผฐ๋‹ค๋Š” ๋ง์€ ์•„๋‹ˆ์ง€๋งŒ, ๋‚˜๋Š” ์—ฌ์ „ํžˆ ๊ธฐ์—ฌํ•˜๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์žˆ์ง€๋งŒ ์œ ์ง€ ๋ฐ ๊ฒ€ํ† ํ•˜๊ธฐ ์–ด๋ ค์šด ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค. ์ฝ”๋“œ ์ž‘์„ฑ์˜ ๋ณต์žก์„ฑ์ด ์•„๋‹ˆ๋ผ ์ฝ”๋“œ๋ฅผ ์ฝ๊ณ  ์ž„์‹œ ์ƒํƒœ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ฒ˜๋ฆฌํ–ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ณต์žก์„ฑ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์žฅํ™ฉํ•œ ๋‹ต๋ณ€์— ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ฌธ์ œ๋ฅผ ์ˆ˜์‹œ๋กœ ์‚ดํŽด๋ณด๊ณ  ์žˆ์—ˆ๊ณ  Flutter ํŒ€์˜ ๋‹ต๋ณ€์— ๋‹ค์†Œ ๋‹นํ™ฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์•ฑ์„ ์‚ฌ์šฉํ•ด ๋ณด๊ณ  ์ฐจ์ด์ ์„ ์ง์ ‘ ํ™•์ธํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์„ ๋“ค์ด์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์ข…์†์„ฑ์„ ์œ ์ง€ํ•˜๊ฑฐ๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋„ˆ๋ฌด ๋งŽ์ด ํ†ตํ•ฉํ•˜์ง€ ์•Š์œผ๋ ค๋Š” ๋ฐ”๋žŒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ flutter_hook ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํ•ต์‹ฌ ๋ถ€๋ถ„์€ ๊ฝค ์ž˜ ๋ฌธ์„œํ™”๋œ ์ฝ”๋“œ์˜ 500์ค„์— ๋ถˆ๊ณผํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ์ด๊ฒƒ์ด ๋Œ€ํ™”์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค๋ฉด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์ œ 2์„ผํŠธ๋ฅผ ์ฃผ๊ณ  ์ œ ๋ชฉ์†Œ๋ฆฌ๋ฅผ ๋‚ธ ๊ฒƒ์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๊ธฐ๋ถ„์„ ์ƒํ•˜๊ฒŒ ํ•˜์ง€ ์•Š๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. @rrousselGit ์ด ๋งค์šฐ ์ข‹์€ ์ง€์ ์„ ํ•˜๊ณ  ์žˆ๊ณ  ๋ช…ํ™•ํ•˜๋‹ค๊ณ 

์žฅํ™ฉํ•œ ๋‹ต๋ณ€์— ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ฌธ์ œ๋ฅผ ์ˆ˜์‹œ๋กœ ์‚ดํŽด๋ณด๊ณ  ์žˆ์—ˆ๊ณ  Flutter ํŒ€์˜ ๋‹ต๋ณ€์— ๋‹ค์†Œ ๋‹นํ™ฉํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์•ฑ์„ ์‚ฌ์šฉํ•ด ๋ณด๊ณ  ์ฐจ์ด์ ์„ ์ง์ ‘ ํ™•์ธํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์„ ๋“ค์ด์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ณต์ •ํ•˜๊ฒŒ ๋งํ•˜์ž๋ฉด ์ด๊ฒƒ์€ ์—„์ฒญ๋‚˜๊ฒŒ ๊ธด ์Šค๋ ˆ๋“œ์ด๋ฉฐ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์„ค๋ฆฝ์ž๋Š” ์—ฌ๋Ÿฌ ์†”๋ฃจ์…˜์œผ๋กœ ๋งค์ผ ์—ฌ๋Ÿฌ ๋ฒˆ ์ ๊ทน์ ์œผ๋กœ ๊ธฐ์—ฌํ•˜๊ณ  ์ด์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ์š”์ฒญํ•˜๊ณ  ์ฐธ์—ฌํ•˜๊ณ  ์š”์ฒญ๋œ ๋‚ด์šฉ์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์†”์งํžˆ ๋„์›€์ด ๋˜๋Š” ์œ ์ง€ ๋ณด์ˆ˜์˜ ๋ช…ํ™•ํ•œ ์˜ˆ๋ฅผ ์ƒ๊ฐํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ๊ตฐ๋ถ„ํˆฌํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ์กฐ๊ธˆ ๋” ์ธ๋‚ด์‹ฌ์ด ์žˆ์—ˆ์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ๋ฅผ ์ฝ์€ ํ›„ ํ›„ํฌ๋ฅผ ๋” ๊นŠ์ด ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋‹จ, ์ผํšŒ์šฉ ์ œํ’ˆ์˜ ์ˆ˜๋ช…์„ State์— ๋ฌถ๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด๋ผ๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์Šคํƒ€์ผ์ ์œผ๋กœ ์„ ํ˜ธํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ž…์žฅ์ด '์‹œ๊ฐ„์„ ๋“ค์—ฌ ํŒจ๋Ÿฌ๋‹ค์ž„์—์„œ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ์•ฑ์„ ์ž‘์„ฑํ•˜๋ฉด ๊ทผ๋ณธ์ ์œผ๋กœ ๊ฒฐํ•จ์ด ์žˆ๋Š” ๋ฌด์–ธ๊ฐ€๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์™œ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋ผ์›Œ๋„ฃ์–ด์•ผ ํ•˜๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค! ' - React ์—”์ง€๋‹ˆ์–ด๊ฐ€ ์ด ์Šค๋ ˆ๋“œ์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด Flutter์—๋Š” ์‹ค์ œ๋กœ ๊ถŒ์žฅ๋˜์ง€ ์•Š์œผ๋ฉฐ ์ด ์Šค๋ ˆ๋“œ์—์„œ ์„ค๋ช…ํ•˜๋Š” ์ด์ ์€ ์žฌ๋ฐฐ์„ ์˜ ๋น„์šฉ์— ๋น„ํ•ด ์ž‘์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ด์ ์„ ๋ณด๋ ค๋ฉด ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ์ฝ”๋“œ๋ฒ ์ด์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์†”์งํžˆ ๋„์›€์ด ๋˜๋Š” ์œ ์ง€ ๋ณด์ˆ˜์˜ ๋ช…ํ™•ํ•œ ์˜ˆ๋ฅผ ์ƒ๊ฐํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ๊ตฐ๋ถ„ํˆฌํ•ฉ๋‹ˆ๋‹ค.

๋™์˜. ์‹œ๊ฐ„์„ ๋‚ด์–ด ์ด ํ† ๋ก ์— ์ฐธ์—ฌํ•ด ์ฃผ์‹  Hixie์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ๋ฅผ ์ฝ์€ ํ›„ ํ›„ํฌ๋ฅผ ๋” ์ด์ƒ ๊นŠ์ด ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๊ณต์ •ํ•˜๊ฒŒ ๋งํ•˜๋ฉด ์ด ๋ฌธ์ œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ํ›„ํฌ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ํ•ด๊ฒฐ์ฑ…๋ณด๋‹ค ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๋Š” ๊ฒƒ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ๋Š๋ผ์‹ญ๋‹ˆ๊นŒ?

์ €๋Š” ์—ฌ๊ธฐ์„œ ์–‘์ชฝ( @rrousselGit ๋ฐ @Hixie)์„ ๋Š๋‚„ ์ˆ˜ ์žˆ์œผ๋ฉฐ Flutter ํ”„๋ ˆ์ž„์›Œํฌ์˜ (๋‚ด) ์‚ฌ์šฉ ์ธก๋ฉด/๊ด€์ ์—์„œ ํ”ผ๋“œ๋ฐฑ์„ ๋‚จ๊ธฐ๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

flutter_hooks ์ ‘๊ทผ ๋ฐฉ์‹์€ ์ƒ์šฉ๊ตฌ๋ฅผ ์ƒ๋‹นํžˆ ์ค„์ด๊ณ (์ด๋Ÿฌํ•œ ์ƒํƒœ ๊ตฌ์„ฑ์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋œ ์˜ˆ์—์„œ๋งŒ) ๋ฆฌ์†Œ์Šค ์ดˆ๊ธฐํ™”/ํ๊ธฐ์— ๋Œ€ํ•ด ์ ๊ทน์ ์œผ๋กœ ์ƒ๊ฐํ•  ํ•„์š”๊ฐ€ ์—†์–ด ๋ณต์žก์„ฑ์„ ์ค„์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋งํ•˜์ž๋ฉด Flutter ์ž์ฒด์˜ "ํ•ต์‹ฌ"์— (์ฃผ๊ด€์ ์œผ๋กœ) ์ž˜ ๋งž์ง€๋Š” ์•Š์ง€๋งŒ ๊ฐœ๋ฐœ ํ๋ฆ„/์†๋„๋ฅผ ๊ฐœ์„ ํ•˜๊ณ  ์ง€์›ํ•˜๋Š” ๋ฐ ์ข‹์€ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ์˜ 95% ์ด์ƒ์€ ๋นŒ๋“œ ๋ฉ”์„œ๋“œ๊ฐ€ ์„ ์–ธ์ ์ผ ๋ฟ์ด๊ณ  ๋กœ์ปฌ ๋ณ€์ˆ˜๋‚˜ ๋ฐ˜ํ™˜๋œ ์œ„์ ฏ ํ•˜์œ„ ํŠธ๋ฆฌ ์™ธ๋ถ€์˜ ํ˜ธ์ถœ์ด ์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ชจ๋“  ๋…ผ๋ฆฌ ๋ถ€๋ถ„์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์ดˆ๊ธฐํ™”, ํ• ๋‹น ๋ฐ ์‚ญ์ œํ•˜๊ณ  ๋ฆฌ์†Œ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ƒํƒœ ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒญ์ทจ์ž(์ œ ๊ฒฝ์šฐ์—๋Š” MobX ๋ฐ˜์‘) ๋ฐ ๊ทธ๋Ÿฌํ•œ ๋…ผ๋ฆฌ์ ์ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Flutter ์ž์ฒด์˜ ๋Œ€๋ถ€๋ถ„์˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด๊ธฐ๋„ ํ•˜๋ฏ€๋กœ ๋งค์šฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๋‹น์‹ ์ด ํ•˜๋Š” ์ผ์— ๋Œ€ํ•ด ํ•ญ์ƒ ๋ช…์‹œ์ ์ด๊ณ  ๊ฐœ๋ฐฉ์ ์ผ ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๋ฅผ ์ฃผ๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋Ÿฌํ•œ ์œ„์ ฏ์„ ํ•ญ์ƒ StatefulWidget ๋ณ€ํ™˜ํ•˜๊ณ  initState / dispose์— ์œ ์‚ฌํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ญ์ƒ ์ •ํ™•ํžˆ ๋ฌด์—‡์„ ํ•˜๋ ค๋Š”์ง€ ์ •ํ™•ํžˆ ๊ธฐ๋กํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์œ„์ ฏ์ด ์‚ฌ์šฉ ์ค‘์ธ ์œ„์ ฏ์— ์ง์ ‘ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ @Hixie๊ฐ€ ์ด๋ฏธ ์ž์‹ ์„ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์–ด๋–ค ์‹์œผ๋กœ๋“  ๊ท€์ฐฎ๊ฒŒ ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๊ฐœ๋ฐœ์ž๋กœ์„œ flutter_hooks ์— ์˜์กดํ•˜๋Š” ๋Œ€์‹  ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค flutter_hooks ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค ์ƒํƒœ๋ฅผ ํ›„ํฌ๋กœ ์ž‘์„ฑํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š”์ง€์— ๋Œ€ํ•ด ์—ฌ์ „ํžˆ ์ƒ๊ฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ’๋ฏธ๋Š” ๋‹ค์–‘ํ•œ "๋‹จ์ผ" ์‚ฌ์šฉ ํ›„ํฌ๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ํ›„ํฌ๋ฅผ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ์„ ๋„ˆ๋ฌด ์ž์ฃผ ์žฌ์‚ฌ์šฉํ•˜์ง€ ์•Š์ง€๋งŒ ๋” ๋งŽ์€ ์‚ฌ์šฉ์ž ์ •์˜ ๊ตฌ์„ฑ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์˜คํ•ดํ•˜์ง€ ๋งˆ์„ธ์š”. ์ด๋Ÿฌํ•œ ํ›„ํฌ์˜ ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋งค์šฐ ํ›Œ๋ฅญํ•˜๊ณ  ์œ ์šฉํ•ด ๋ณด์ด์ง€๋งŒ ์ €์—๊ฒŒ๋Š” ์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์˜ ํ•ต์‹ฌ ๊ฐœ๋…์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋งค์šฐ ๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋…์ฒ˜๋Ÿผ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ "๊ธฐ๋ณธ์ ์œผ๋กœ" ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋งŒ์กฑํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์ด๋Ÿฌํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๋ฅผ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ œ๊ณตํ•˜๋Š” ํŒจํ‚ค์ง€ ์ž์ฒด๋กœ์„œ ๋งค์šฐ ๊ธฐ๋ถ„์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํ†ตํ•ฉ๋˜๋ฉด ์ด ๊ฐœ๋…์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Flutter์˜ ํฐ ๋ถ€๋ถ„์„ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜(๋งŽ์€ ์ž‘์—…) ๋ฏธ๋ž˜/์„ ํƒ๋œ ํ•ญ๋ชฉ์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(์ด๋Ÿฌํ•œ ํ˜ผํ•ฉ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ˜ผ๋ž€์Šค๋Ÿฌ์šธ ์ˆ˜ ์žˆ์Œ).

Flutter ํ”„๋ ˆ์ž„์›Œํฌ ์ž์ฒด์— ํ†ตํ•ฉ๋˜๊ณ  ์ง€์›/ํ™œ์šฉ๋œ๋‹ค๋ฉด ๋ถ„๋ช…ํžˆ ์—ฌ๊ธฐ์— ๋›ฐ์–ด๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์ดํ•ดํ•˜๊ณ  ์‹ฌ์ง€์–ด ์ข‹์•„ํ•˜๋ฉฐ ์ด๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ (๊ฐ€๋Šฅํ•œ) ์กฐ์น˜๋ฅผ ๋ณด์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์ € ๋ฐ/๋˜๋Š” ์ˆ˜ํ–‰ํ•ด์„œ๋Š” ์•ˆ ๋˜๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๊ณ  ํŒจํ‚ค์ง€๋กœ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ํ‹€๋ ธ๋‹ค๋ฉด ์ •์ •ํ•ด ์ฃผ์„ธ์š”. ํ•˜์ง€๋งŒ ์ด ์Šค๋ ˆ๋“œ๋Š” ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•˜๊ณ  ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ๋ฐฉ์‹์œผ๋กœ ์—ฌ๋Ÿฌ ์œ„์ ฏ์—์„œ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฌธ์ œ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ ํ›„ํฌ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด ์Šค๋ ˆ๋“œ๊ฐ€ ํ•ด๊ฒฐ์ฑ…์ด ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•œ ๊ณต๊ฐœ์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ† ๋ก ์„ ํ•˜๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ด๋ฆฐ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ํ•˜๋‚˜์˜ ์†”๋ฃจ์…˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์–ธ๊ธ‰๋˜์—ˆ์ง€๋งŒ @rrousselGit ์ด ์—ฌ๊ธฐ์—์„œ ์‚ฌ์šฉํ•˜์—ฌ ๊ทธ๋“ค์ด ํ•ด๊ฒฐํ•˜๋Š” ๋ฌธ์ œ/๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๊ณ (์†”๋ฃจ์…˜์ด๊ธฐ ๋•Œ๋ฌธ์—) ํ”Œ๋Ÿฌํ„ฐ์— ๋” ๊ณ ์œ ํ•œ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์ด ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค. ์™€ ํ•จ๊ป˜ ์ œ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ์žฌ์‚ฌ์šฉ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์ง€๋งŒ ์ด ์Šค๋ ˆ๋“œ์— ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์ด ์ œ์‹œ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๊นŒ?

์ฆ‰, ์Šค๋ ˆ๋“œ๊ฐ€ ํ˜„์žฌ ์–ด๋””๋กœ ๊ฐ€๊ณ  ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.
๋ฌธ์ œ๊ฐ€ ์‹ค์ œ๋กœ ์กด์žฌํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์•„๋‹ˆ๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์ด๊ฒƒ์„ ํ† ๋ก ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?
์˜ค๋Š˜๋‚  Flutter์˜ ํ•ต์‹ฌ์ด ์žˆ๋Š” ์—ฌ๋Ÿฌ ์œ„์ ฏ์—์„œ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ๋ฐฉ์‹์œผ๋กœ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ต๋‹ค๋Š” ๋ฐ ๋ชจ๋‘ ๋™์˜ํ•œ๋‹ค๋ฉด ํ•ต์‹ฌ ์†”๋ฃจ์…˜์ด ๋  ์ˆ˜ ์žˆ๋Š” ์†”๋ฃจ์…˜์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋นŒ๋”๋Š” ์‹ค์ œ๋กœ (์ธ์šฉํ•˜๊ธฐ ์œ„ํ•ด)

๊ฐ€๋…์„ฑ์ด ํ˜„์ €ํžˆ ๋–จ์–ด์ง

์†์„ฑ ์†”๋ฃจ์…˜์€ ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ ๊ฐ™๊ฑฐ๋‚˜ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋‹ต๋ณ€์ด ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž˜๋ชป๋œ ๊ฒฐ๋ก ์„ ๋‚ด๋ ธ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋‹ค๋ฅธ ์œ„์ ฏ์˜ _ExampleState ๋‚ด๋ถ€์— ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ณด์กฐ ์œ„์ ฏ์„ ๋งŒ๋“œ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?
ํŠธ์œ„์ŠคํŠธ: ์ƒˆ ์œ„์ ฏ์€ State ๋‚ด๋ถ€์—์„œ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ์ž ID๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@timsneath๊ฐ€ ์ œ์•ˆํ•œ ๋Œ€๋กœ ์„ค๊ณ„ ๋ฌธ์„œ๋ฅผ ๊ธฐ๊บผ์ด ๋„์™€๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์‚ฌ๋ก€ ์—ฐ๊ตฌ ์‚ฌ๋ก€๋กœ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๊ณ  ๋‹ค์–‘ํ•œ ์†”๋ฃจ์…˜์„ ์–ธ๊ธ‰ํ•˜๊ณ  Flutter์— ๋งž๋Š” ์†”๋ฃจ์…˜์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š”์ง€ ํƒ์ƒ‰ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€ ํ˜•์‹์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋…ผ์˜๊ฐ€ ๋‹ค์†Œ ๊ธธ์„ ์žƒ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ํ˜„์žฌ ๋””์ž์ธ ๋ฌธ์„œ๋ฅผ ๋งŒ๋“œ๋Š” ์•„์ด๋””์–ด์— ๋Œ€ํ•ด ์ƒ๋‹นํžˆ ํšŒ์˜์ ์ž…๋‹ˆ๋‹ค.
ํ˜„์žฌ @Hixie ๋Š” Flutter ๋‚ด์—์„œ ์ด ๋ฌธ์ œ๋ฅผ ์ง์ ‘ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์— ๋ฐ˜๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

์ œ๊ฐ€ ๋ณด๊ธฐ์—๋Š” ๋ฌธ์ œ์˜ ์ค‘์š”์„ฑ๊ณผ ๊ทธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” Google์˜ ์—ญํ• ์— ๋Œ€ํ•ด ์˜๊ฒฌ์ด ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
์–‘์ธก์ด ์ด์— ๋™์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ํ•ด๊ฒฐ์ฑ…์ด ๋ฌด์—‡์ด๋“  ๊ฐ„์— ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ์‚ฐ์ ์ธ ํ† ๋ก ์„ ํ•  ์ˆ˜ ์žˆ์„์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ ์Šค๋ ˆ๋“œ๋Š” ๋งค์šฐ ํฅ๋ฏธ๋กญ๊ฒŒ ์ฝ์—ˆ์œผ๋ฉฐ ๊ด€์ ์˜ ๊ตํ™˜์ด ์—ฌ์ „ํžˆ ์‹œ๋ฏผ์ ์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ํ˜„์žฌ์˜ ๋‚œ๊ตญ์— ์•ฝ๊ฐ„ ๋†€๋ž์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ์™€ ๊ด€๋ จํ•˜์—ฌ ๋‚ด ๊ฒฌํ•ด๋Š” Flutter๊ฐ€ @rrousselGit ์—์„œ ์ œ๊ณตํ•˜๋Š” ํŠน์ • ํ›„ํฌ ์†”๋ฃจ์…˜์ด ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ๊ทธ๋ ‡๋‹ค๊ณ  ๋งํ•˜์ง€๋„ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Remi์™€ ๋‹ค๋ฅธ ์ง€์ง€์ž๋“ค์ด ์–ธ๊ธ‰ํ•œ ๋ชจ๋“  ์ด์œ  ๋•Œ๋ฌธ์— Flutter๋Š” ํ›„ํฌ์™€ ์œ ์‚ฌํ•œ ์ด์ ์„ ์ œ๊ณตํ•˜๋Š” ์†”๋ฃจ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. @emanuel-lundman์€ ์œ„์˜ ์ฃผ์žฅ์„ ์ž˜ ์š”์•ฝํ–ˆ์œผ๋ฉฐ ๋‚˜๋Š” ๊ทธ์˜ ๊ฒฌํ•ด์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๋‹ค๋ฅธ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ œ์•ˆ์ด ์—†๊ณ  ํ›„ํฌ๊ฐ€ React์—์„œ ์ž˜ ์ž…์ฆ๋œ ์‹ค์ ์„ ๊ฐ–๊ณ  ์žˆ๊ณ  Flutter๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ์กด ์†”๋ฃจ์…˜์ด ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊ฐ์•ˆํ•  ๋•Œ ์ œ ์ƒ๊ฐ์—๋Š” ๊ทธ๋ ‡์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ์€ ๋‚˜์œ ์„ ํƒ์ž…๋‹ˆ๋‹ค. ํ›„ํฌ ๊ฐœ๋…์€ Flutter SDK(๋˜๋Š” ๊ทธ ์ดํ•˜)์—๋„ ํฌํ•จ๋œ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋กœ์„œ Flutter์—์„œ ์–ด๋–ค ๊ฒƒ๋„ ๋นผ์•—์•„ ๊ฐˆ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ œ ์ƒ๊ฐ์—๋Š” Flutter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ํ’๋ถ€ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์œ ์ง€ ๊ด€๋ฆฌ ๊ฐ€๋Šฅํ•˜๊ณ  ์ฆ๊ฑฐ์šด ์•ฑ์„ ํ›จ์”ฌ ๋” ์‰ฝ๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ›„ํฌ๊ฐ€ ํ˜œํƒ์„ ๋ฐ›๊ณ ์ž ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ ํŒจํ‚ค์ง€๋กœ ์ œ๊ณต๋œ๋‹ค๋Š” ์ฃผ์žฅ์€ ์ผ๋ฆฌ๊ฐ€ ์žˆ๋Š” ๋ง์ด์ง€๋งŒ, ํ›„ํฌ์™€ ๊ฐ™์€ ์›์‹œ์ ์ธ ๊ฒฝ์šฐ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๋ถ€์ ์œผ๋กœ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค ๋•Œ ์šฐ๋ฆฌ๋Š” ์ข…์ข… Dart+Flutter SDK์—๋งŒ ์˜์กดํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์—์„œ ํŒจํ‚ค์ง€๊ฐ€ "์ˆœ์ˆ˜"ํ•ด์•ผ ํ•˜๋Š”์ง€ ๋˜๋Š” ๊ทธ ์•ˆ์— ๋‹ค๋ฅธ ํŒจํ‚ค์ง€๋ฅผ ํ—ˆ์šฉํ•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๋Œ€ํ•ด ํ† ๋ก ํ•ฉ๋‹ˆ๋‹ค. ๊ฒƒ. ์‹ฌ์ง€์–ด Provider๋Š” "์ˆœ์ˆ˜ํ•œ" ํŒจํ‚ค์ง€๋ฅผ ์œ„ํ•ด ๋‚˜์˜ค์ง€๋งŒ ์ข…์ข… ๋” ๋†’์€ ์ˆ˜์ค€์˜ ํŒจํ‚ค์ง€๋ฅผ ์œ„ํ•ด ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค. ์•ฑ์˜ ๊ฒฝ์šฐ ์–ด๋–ค ํŒจํ‚ค์ง€๊ฐ€ ๊ดœ์ฐฎ์€์ง€ ์•„๋‹Œ์ง€์— ๋Œ€ํ•œ ๋™์ผํ•œ ๋…ผ์Ÿ์ด ํ•ญ์ƒ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณต๊ธ‰์ž๋Š” ๋…น์ƒ‰์ด์ง€๋งŒ Hooks์™€ ๊ฐ™์€ ๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹ํŒจํ‚ค์ง€๋กœ ๋ฌผ์Œํ‘œ์ž…๋‹ˆ๋‹ค.

์†”๋ฃจ์…˜๊ณผ ๊ฐ™์€ ํ›„ํฌ๊ฐ€ SDK์˜ ์ผ๋ถ€์ธ ๊ฒฝ์šฐ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ถ„๋ช…ํ•œ ์„ ํƒ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. Hooks๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ด๋ฏธ ํŒจํ‚ค์ง€๋กœ ํ—ˆ์šฉํ•˜๊ณ  ์‹ถ์ง€๋งŒ, ์ด๊ฒƒ์ด Flutter ์ฝ”๋“œ ์Šคํƒ€์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” Flutter ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ต์ˆ™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋…์„ ๋„์ž…ํ•˜๋Š” ๊ฒƒ๋„ ๊ฑฑ์ •๋ฉ๋‹ˆ๋‹ค. SDK์—์„œ ์ง€์›ํ•˜์ง€ ์•Š๊ณ  ์ด ๊ธธ์„ ๊ฐ„๋‹ค๋ฉด ๊ฐˆ๋ฆผ๊ธธ ๊ฐ™์€ ๋Š๋‚Œ์ด ๋“ญ๋‹ˆ๋‹ค. ์†Œ๊ทœ๋ชจ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ Hooks๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์‰ฌ์šด ์„ ํƒ์ž…๋‹ˆ๋‹ค. Riverpod์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

(์ €ํฌ ํŒจํ‚ค์ง€ ๋ณด์ˆ˜์ฃผ์˜๋Š” ๊ณผ๊ฑฐ์— ๋‹ค๋ฅธ ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž์— ๋Œ€ํ•œ ํŒจํ‚ค์ง€ ๋ฐ ์ข…์†์„ฑ ์—‰๋ง์œผ๋กœ ์ธํ•ด ํ™”์ƒ์„ ์ž…์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋งˆ๋„ ๊ณ ์œ ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

์ง€๊ธˆ๊นŒ์ง€ ์œ ์ผํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š” ์‹œ์—ฐ๋œ ์†”๋ฃจ์…˜์ด๋ผ ํ• ์ง€๋ผ๋„ ํ›„ํฌ๊ฐ€ ํ˜„์žฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์†”๋ฃจ์…˜์— ์ปค๋ฐ‹ํ•˜๊ธฐ ์ „์— ๋ณด๋‹ค ์ผ๋ฐ˜์ ์ธ ์ˆ˜์ค€์—์„œ ์˜ต์…˜์„ ์กฐ์‚ฌํ•˜๋Š” ๊ฒƒ์€ ํ™•์‹คํžˆ ํฅ๋ฏธ๋กญ๊ณ  ์œ ํšจํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” Flutter SDK๊ฐ€ _ํ˜„์žฌ ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ ๋…ผ๋ฆฌ์™€ ๊ด€๋ จํ•˜์—ฌ ๊ฒฐํ•จ์ด ์žˆ์Œ์„ ์ธ์‹ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ •๊ตํ•œ ์„ค๋ช…์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ํ˜„์žฌ ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ €์—๊ฒŒ๋Š” Hooks๋ฅผ ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋„ฃ์ง€ ์•Š๋Š” ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋Š” API์— ์œ„ํ—˜ํ•œ ํ•จ์ •์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž˜๋ชป๋œ ์ˆœ์„œ๋กœ ํ›„ํฌ๋ฅผ ์–ด๋–ป๊ฒŒ๋“  ํ˜ธ์ถœํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์น˜๋ช…์ ์ธ ๋ฌธ์ œ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ๊ทœ์œจ์„ ๋”ฐ๋ฅด๊ณ  ๋ฌธ์„œ๋ฅผ ๋”ฐ๋ฅด๋ฉด ํ”ผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ฌธ์ œ์— ๋Œ€ํ•œ IMHO์˜ ์ข‹์€ ์†”๋ฃจ์…˜์—๋Š” ๊ทธ๋Ÿฐ ๊ฒฐํ•จ์ด ์—†๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ๋Š” ์‚ฌ๋žŒ๋“ค์ด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Hooks(๋˜๋Š” ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๊ฐ€ ์—†์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ œ ์‚ฌ๋žŒ๋“ค์ด ๋…ผ์˜ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ Hooks๋Š” ํŠนํžˆ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด Hooks๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ์‚ฌ๋žŒ๋“ค์ด ๊ด€๋ จ ์—†๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ hooks๋ฅผ ์ง€์›ํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž„ ๋งŒํผ ์ถฉ๋ถ„ํžˆ ๋ถ€๋‹ด์Šค๋Ÿฝ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์€ ๊ทธ๋Ÿด ํ•„์š”๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ข‹์€ ์†”๋ฃจ์…˜์€ ๋‹จ๋…์œผ๋กœ ์กด์žฌํ•˜๋ฉฐ ๋‹ค๋ฅธ ๋ชจ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด์— ๋Œ€ํ•ด ์•Œ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ตœ๊ทผ์— ํ”„๋ ˆ์ž„์›Œํฌ์— RestorableProperties๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์ด ์—ฌ๊ธฐ์—์„œ ์–ด๋–ป๊ฒŒ๋“  ํ™œ์šฉ๋  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ณด๋Š” ๊ฒƒ์€ ํฅ๋ฏธ๋กœ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค...

๋‚˜๋Š” ๋ถ„์„๊ธฐ ๋˜๋Š” ๋ฆฐํ„ฐ๊ฐ€ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ์ˆจ๊ฒจ์ง„ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” API์— ๋Œ€ํ•ด @Hixie ๊ฐ€ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์ฐธ์—ฌ๋ฅผ ์›ํ•˜๋Š” ์‚ฌ๋žŒ์ด๋ผ๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์„ค๊ณ„ ๋ฌธ์„œ ์ œ์•ˆ์„ ํ†ตํ•ด, ์•„๋‹ˆ๋ฉด ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๊ด€๋ฆฌ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋‹ค์–‘ํ•œ ์†”๋ฃจ์…˜์„ ๋ชจ์ƒ‰ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” ๋” Flutter์— ๊ณ ์œ ํ•˜๊ณ  Flutter API๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋™์‹œ์— hook API๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Vue ๋ฒ„์ „์€ ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ํ›„ํฌ ํ˜ธ์ถœ ์ˆœ์„œ์— ์˜์กดํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์‹œ์ž‘ํ•˜๊ธฐ์— ์ข‹์€ ๋ชจ๋ธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์™€ ํ•จ๊ป˜ ์กฐ์‚ฌํ•˜๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์žˆ๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@Hixie ํ•˜์ง€๋งŒ ์œ„์ ฏ ๊ฐ„์— ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ๋ฐฉ์‹์œผ๋กœ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์—†๋‹ค๋Š” ๋ฌธ์ œ์— ๋™์˜ํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋ž˜์„œ ResuableProperties๋ฅผ ์–ด๋–ป๊ฒŒ๋“  ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๊นŒ?

์ €์—๊ฒŒ๋Š” Hooks๋ฅผ ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋„ฃ์ง€ ์•Š๋Š” ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋Š” API์— ์œ„ํ—˜ํ•œ ํ•จ์ •์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž˜๋ชป๋œ ์ˆœ์„œ๋กœ ํ›„ํฌ๋ฅผ ์–ด๋–ป๊ฒŒ๋“  ํ˜ธ์ถœํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์น˜๋ช…์ ์ธ ๋ฌธ์ œ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ๊ทœ์œจ์„ ๋”ฐ๋ฅด๊ณ  ๋ฌธ์„œ๋ฅผ ๋”ฐ๋ฅด๋ฉด ํ”ผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ฌธ์ œ์— ๋Œ€ํ•œ IMHO์˜ ์ข‹์€ ์†”๋ฃจ์…˜์—๋Š” ๊ทธ๋Ÿฐ ๊ฒฐํ•จ์ด ์—†๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ์™€ ํ•จ๊ป˜ ์ž‘์—…ํ•˜๊ณ  ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ํ•จ๊ป˜ ์ž‘์—…ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ํฐ ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๋“ค์ด ํ…Œ์ด๋ธ”์— ๊ฐ€์ ธ์˜ค๋Š” ๋ชจ๋“  ํฐ ์ด์ (๊ฐœ๋ฐœ ์†๋„, ์žฌ์‚ฌ์šฉ์„ฑ, ๊ตฌ์„ฑ ๊ฐ€๋Šฅ์„ฑ ๋ฐ ์‰ฝ๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ์˜ ํฐ ์ด์ )๊ณผ ์ „ํ˜€ ๋น„๊ต๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
ํ›„ํฌ๋Š” ํ›„ํฌ์ž…๋‹ˆ๋‹ค. ๋งˆ์น˜ ํด๋ž˜์Šค๊ฐ€ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹Œ ํด๋ž˜์Šค์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์กฐ๊ฑด๋ถ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ ๋นจ๋ฆฌ ๋ฐฐ์›๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹น์‹ ์˜ ํŽธ์ง‘์ž๋„ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋„์›€์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ๋Š” ์‚ฌ๋žŒ๋“ค์ด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Hooks(๋˜๋Š” ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๊ฐ€ ์—†์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ œ ์‚ฌ๋žŒ๋“ค์ด ๋…ผ์˜ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ Hooks๋Š” ํŠนํžˆ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด Hooks๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ์‚ฌ๋žŒ๋“ค์ด ๊ด€๋ จ ์—†๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ hooks๋ฅผ ์ง€์›ํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž„ ๋งŒํผ ์ถฉ๋ถ„ํžˆ ๋ถ€๋‹ด์Šค๋Ÿฝ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์€ ๊ทธ๋Ÿด ํ•„์š”๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ข‹์€ ์†”๋ฃจ์…˜์€ ๋‹จ๋…์œผ๋กœ ์กด์žฌํ•˜๋ฉฐ ๋‹ค๋ฅธ ๋ชจ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด์— ๋Œ€ํ•ด ์•Œ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ถ€๋‹ด์Šค๋Ÿฝ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
ํ˜„์žฌ IMHO์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์†”๋ฃจ์…˜๋ณด๋‹ค ์—ฌ์ „ํžˆ ์‰ฝ์Šต๋‹ˆ๋‹ค(ํ•ด๋‹น ๋ฌธ๊ตฌ๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๐Ÿ˜‰).
์ œ๊ฐ€ ๊ธ€์„ ์ž˜๋ชป ์ดํ•ดํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„๋ฌด๋„ ๊ทธ๋Ÿฐ ๋ง์„ ํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์€๋ฐ?
์‚ฌ๋žŒ๋“ค์ด ํ›„ํฌ ์†”๋ฃจ์…˜์ด ํ…Œ์ด๋ธ”์— ๊ฐ€์ ธ๋‹ค์ฃผ๋Š” ๋ชจ๋“  ์ด์ ์„ ์ •๋ง๋กœ ๊ฐ์‚ฌํ•˜๊ฒŒ ์—ฌ๊ธฐ๊ณ  ๋ชจ๋“  ๊ณณ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ผ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ฝ์—ˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ํ˜œํƒ์„ ๋ˆ„๋ฆฌ๊ธฐ ์œ„ํ•ด. ํ›„ํฌ๋Š” ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํƒ€์‚ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž์‹ ์˜ ๋ž˜ํผ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ์ž์‹ ์˜ ํ›„ํฌ๋ฅผ ์ฝ”๋”ฉํ•˜๊ณ  ๋ฐฐ์†กํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ด์ ์„ ์–ป์œผ์‹ญ์‹œ์˜ค.
@rrousselGit ๊ณผ @gaearon ์ด ์ด๋ฏธ ์›์‹œ์ ์ธ ๊ฒƒ์„ ์„ค๋ช…ํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋“ค์–ด๊ฐ€์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.
์•„๋งˆ๋„ ์ด ๊ธ€์ด ์‚ฌ๋žŒ๋“ค์ด ์ด ์Šค๋ ˆ๋“œ์— ์ž‘์„ฑํ•œ ๋‚ด์šฉ์„ ์ž˜ ์š”์•ฝํ•œ ๊ฒƒ์ธ์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ดํ•ดํ•˜์ง€ ๋ชปํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

์•ž์œผ๋กœ ๋ฐฉ๋ฒ•์ด ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ ์–ด๋„ ์ด๊ฒƒ์ด ๋ฌธ์ œ๋ผ๋Š” ๋ฐ ๋™์˜ํ•˜๊ณ  ํ›„ํฌ๊ฐ€ ํ…Œ์ด๋ธ” ์œ„์— ์žˆ์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— ๋” ๋‚˜์€ ๋Œ€์ฒด ์†”๋ฃจ์…˜์„ ์ƒ๊ฐํ•ด ๋‚ด์•ผ ํ•  ๋•Œ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
์•„๋‹ˆ๋ฉด ๊ทธ๋ƒฅ ํ”Œ๋Ÿฌํ„ฐ ์ฝ”์–ด์—์„œ ๋ฌธ์ œ ์ˆ˜์ •์„ ๊ฑด๋„ˆ๋›ฐ๊ธฐ๋กœ ๊ฒฐ์ •ํ•˜์‹ญ์‹œ์˜ค.

๋ˆ„๊ฐ€ ์•ž์œผ๋กœ์˜ ๊ธธ์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๊นŒ?
๋‹ค์Œ ๋‹จ๊ณ„๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์น˜๋ช…์ ์ธ ๋ฌธ์ œ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ๊ทœ์œจ์„ ๋”ฐ๋ฅด๊ณ  ๋ฌธ์„œ๋ฅผ ๋”ฐ๋ฅด๋ฉด ํ”ผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ฌธ์ œ์— ๋Œ€ํ•œ IMHO์˜ ์ข‹์€ ์†”๋ฃจ์…˜์—๋Š” ๊ทธ๋Ÿฐ ๊ฒฐํ•จ์ด ์—†๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.

React์—์„œ๋Š” ์ •์  ๋ถ„์„์ธ linter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๊ฒฝํ—˜์ƒ ์ด ๊ฒฐํ•จ์€ ๋Œ€๊ทœ๋ชจ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ๋„ ์ค‘์š”ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๊ฒฐํ•จ์œผ๋กœ ๊ฐ„์ฃผํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ์žˆ์ง€๋งŒ ์ง€์† ํ˜ธ์ถœ ์ˆœ์„œ์— ์˜์กดํ•˜๋Š” ๊ฒƒ์ด ์‚ฌ๋žŒ๋“ค์ด ์ง๊ด€์  ์œผ๋กœ ๋ฌธ์ œ๊ฐ€ ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋ฐ˜๋ฉด ๊ท ํ˜•์€ ์‹ค์ œ๋กœ๋Š” ์ƒ๋‹นํžˆ ๋‹ค๋ฅด๋‹ค๋Š” ์ ์„ ์ง€์ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ด ๋Œ“๊ธ€์„ ์“ฐ๋Š” ์ง„์งœ ์ด์œ ๋Š” Flutter๊ฐ€ ์ปดํŒŒ์ผ๋œ ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. "๋ฆฐํŒ…"์€ ์„ ํƒ ์‚ฌํ•ญ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ˜ธ์ŠคํŠธ ์–ธ์–ด์™€ UI ํ”„๋ ˆ์ž„์›Œํฌ ์‚ฌ์ด์— ์ •๋ ฌ์ด ์žˆ์œผ๋ฉด "์กฐ๊ฑด๋ถ€" ๋ฌธ์ œ๊ฐ€ ์ •์ ์œผ๋กœ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” UI ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์–ธ์–ด ๋ณ€๊ฒฝ(์˜ˆ: Compose + Kotlin)์— ๋™๊ธฐ๋ฅผ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@Hixie ํ•˜์ง€๋งŒ ์œ„์ ฏ ๊ฐ„์— ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ๋ฐฉ์‹์œผ๋กœ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์—†๋‹ค๋Š” ๋ฌธ์ œ์— ๋™์˜ํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋ž˜์„œ ResuableProperties๋ฅผ ์–ด๋–ป๊ฒŒ๋“  ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๊นŒ?

๊ทธ๊ฒƒ์€ ํ™•์‹คํžˆ ์‚ฌ๋žŒ๋“ค์ด ์ œ๊ธฐํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‚ด๊ฐ€ ๋ณธ๋Šฅ์ ์œผ๋กœ ๊ฒฝํ—˜ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. Flutter๋กœ ๋‚ด ์ž์‹ ์˜ ์•ฑ์„ ์ž‘์„ฑํ•  ๋•Œ ๋ฌธ์ œ๋ผ๊ณ  ๋Š๋‚€ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด์„œ ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์‹ค์ œ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์˜๋ฏธ๋Š” ์•„๋‹™๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํƒ€์‚ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž์‹ ์˜ ๋ž˜ํผ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ์ž์‹ ์˜ ํ›„ํฌ๋ฅผ ์ฝ”๋”ฉํ•˜๊ณ  ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ œ ์š”์ ์€ ์—ฌ๊ธฐ์—์„œ ์ข‹์€ ์†”๋ฃจ์…˜์€ ๋ž˜ํผ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ ๋‹จ๊ณ„๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ๋‹จ๊ณ„๊ฐ€ ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์—ฌ๊ธฐ์„œ ์ด์•ผ๊ธฐํ•˜์ง€ ์•Š์€ Flutter์˜ ํŠน์ • ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฌธ์ œ๋ฅผ ์‹ ๊ณ ํ•˜๊ณ  ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜์„ธ์š”.
  • Hooks๋ณด๋‹ค ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ด ๋ฌธ์ œ์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ข‹์€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“œ์‹ญ์‹œ์˜ค.
  • Hooks๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ์žˆ๋‹ค๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•˜์‹ญ์‹œ์˜ค.
  • Hooks์˜ ์ž ์žฌ๋ ฅ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๋Š” Flutter ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ƒˆ ๋ฌธ์ œ๋กœ ์ œ์ถœํ•˜์„ธ์š”.
    ๋“ฑ.

์ด ๋ฌธ์ œ ์Šค๋ ˆ๋“œ๋Š” ๋งค์šฐ ํฅ๋ฏธ๋กญ๊ฒŒ ์ฝ์—ˆ์œผ๋ฉฐ ๊ด€์ ์˜ ๊ตํ™˜์ด ์—ฌ์ „ํžˆ ์‹œ๋ฏผ์ ์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ ๋•Œ ๋ฌด๋ก€ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€๋ณด๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ์—๋Š” ๊ณต๊ฐ์ด ๋„ˆ๋ฌด ์ ์–ด์„œ ์˜†์—์„œ ์ฝ๊ณ  ๋”ฐ๋ผ๊ฐ€๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์ œ ์š”์ ์€ ์—ฌ๊ธฐ์—์„œ ์ข‹์€ ์†”๋ฃจ์…˜์€ ๋ž˜ํผ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ž˜ํผ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ต์ˆ™ํ•ด์ง„ ์ž์‹ ์˜ ์ฝ”๋“œ์—์„œ ์ด์ ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์„ ์–ป๊ณ  ์‹ถ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ›„ํฌ ๋ž˜ํ•‘ ์žฌ๋ฃŒ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ(๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ) ์ด๋Š” ๋ถ€๋‹ด์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ด ์•„๋‹ˆ๋ผ ๋Œ€์•ˆ๋ณด๋‹ค ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ์ข‹์€ ์ด์œ ์ด๋ฉฐ ์ด ์Šค๋ ˆ๋“œ์˜ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด ํ•ต์‹ฌ์ ์ธ ์ด์œ ๋ฅผ ์–ธ๊ธ‰ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ฝ”์–ด์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๋…ผ๋ฆฌ ์†”๋ฃจ์…˜์€ ์ด๋Ÿฌํ•œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋…ผ๋ฆฌ๊ฐ€ ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋“  ํŒจํ‚ค์ง€์— ์•ˆ์ „ํ•˜๊ฒŒ ๋ฐฐ์†ก๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ๋žŒ๋“ค์ด ๋ž˜ํผ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ฝ”์–ด์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๋…ผ๋ฆฌ ์†”๋ฃจ์…˜์€ ์ด๋Ÿฌํ•œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋…ผ๋ฆฌ๊ฐ€ ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋“  ํŒจํ‚ค์ง€์— ์•ˆ์ „ํ•˜๊ฒŒ ๋ฐฐ์†ก๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ๋žŒ๋“ค์ด ๋ž˜ํผ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งํ•˜๋ ค๋Š” ์š”์ ์€ IMHO๊ฐ€ ์ข‹์€ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด _์•„๋ฌด๋„_๊ฐ€ ํ•ด๋‹น ๋…ผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์žฌ์‚ฌ์šฉํ•  ์ค‘๋ณต ๋…ผ๋ฆฌ๊ฐ€ ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ด์ „์˜ "fetchUser" ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด ์•„๋ฌด๋„ "fetchUser" ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ ๋˜๋Š” ์ด์™€ ๋™๋“ฑํ•œ ๊ฒƒ์„ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ "fetchUser" ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์œ ์‚ฌํ•˜๊ฒŒ "fetchUser"๋Š” ํ›„ํฌ(๋˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ)์— ๋Œ€ํ•ด ์•„๋ฌด๊ฒƒ๋„ ์•Œ ํ•„์š”๊ฐ€ ์—†๊ณ  ํ›„ํฌ(๋˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ)๋Š” "fetchUser"์— ๋Œ€ํ•ด ์•„๋ฌด๊ฒƒ๋„ ์•Œ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์‚ฌ์†Œํ•œ ๋…ผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋™์•ˆ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ œํ•œ ์‚ฌํ•ญ์€ ํ›„ํฌ๊ฐ€ ์–ธ์–ด ์ œํ•œ ์‚ฌํ•ญ ์œ„์— ์žˆ๋Š” ํŒจ์น˜๋ผ๋Š” ์‚ฌ์‹ค๋กœ ์ธํ•ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ถ€ ์–ธ์–ด์—์„œ ํ›„ํฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์–ธ์–ด ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

state count = 0;

return RaisedButton(
  onPressed: () => count++,
  child: Text('clicked $count times'),
)

์ด๋Š” ํ˜ธ์ถœ ๊ฐ„์— ์ผ๋ถ€ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๋น„๋™๊ธฐ /๋™๊ธฐํ™” ํ•จ์ˆ˜์˜ ๋ณ€ํ˜•์ž…๋‹ˆ๋‹ค.

์–ธ์–ด์˜ ์ผ๋ถ€๋กœ ์œ ํ˜•์ด ์•„๋‹Œ ์ค„ ๋ฒˆํ˜ธ๋กœ ๊ฐ ๋ณ€์ˆ˜๋ฅผ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋” ์ด์ƒ ์กฐ๊ฑด ์—†๋Š” ์‚ฌ์šฉ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ ์ œํ•œ ์‚ฌํ•ญ์€ --track-widget-creation ์ œํ•œ ์‚ฌํ•ญ๊ณผ ์œ ์‚ฌํ•˜๋‹ค๊ณ  ๋ง๋ถ™์ž…๋‹ˆ๋‹ค.

์ด ํ”Œ๋ž˜๊ทธ๋Š” ์œ„์ ฏ์— ๋Œ€ํ•œ const ์ƒ์„ฑ์ž ์ •๊ทœํ™”๋ฅผ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์œ„์ ฏ์€ ์„ ์–ธ์ ์ด๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ ํ›„ํฌ๋Š” ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ์ œํ•œ ์‚ฌํ•ญ์€ ์„ ์–ธ์ ์œผ๋กœ ์กฐ์ž‘๋˜๋ฏ€๋กœ ์‹ค์ œ๋กœ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๋Š” ๋‹ค๋ฅธ ๊ฒƒ์„ ์ฝ์ง€ ์•Š๊ณ ๋Š” ํ•˜๋‚˜์˜ ๋งค์šฐ ํŠน์ •ํ•œ ํ›„ํฌ๋ฅผ ์–ป์ง€ ๋ชปํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

fetchuser ์˜ˆ์ œ๊ฐ€ ์ด์ƒ์ ์ธ ์˜ˆ์ œ๊ฐ€ ์•„๋‹ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ useStream, useAnimstion ๋˜๋Š” useStreamCinroller๋Š” ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ํ›จ์”ฌ ๋” ๊น”๋”ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  dudChangeDependencues๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ํ˜„์žฌ ๋ฐฉ์‹์€ ํ•จ์ •์— ๋น ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ˜ธ์ถœ ์‹œํ€€์Šค์˜ ์ž ์žฌ์ ์ธ ๋ฌธ์ œ๋Š” ๊ทธ๋ณด๋‹ค ๋” ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹Œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
๋‚ด ์ž์‹ ์˜ ํ›„ํฌ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์‹œ์ž‘ํ• ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ ํ”„๋ ˆ์ž„์›Œํฌ ๋‚ด์—์„œ ์‚ฌ์šฉํ•  ์ค€๋น„๊ฐ€ ๋œ ์ž์ฃผ ํ•„์š”ํ•œ ์ปฌ๋ ‰์…˜์ด ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ์€ ๊ทธ๋“ค์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋Œ€์•ˆ์ ์ธ ๋ฐฉ๋ฒ•์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

@Hixie , ์„ค๋ช…ํ•˜๋ ค๋Š” ๋‚ด์šฉ์„ ํŒŒ์•…ํ•˜์ง€ ๋ชปํ•ด ์ •๋ง ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๋Šฆ์€ ์ €๋…์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์•„๋งˆ ์ €๋งŒ ๊ทธ๋Ÿฐ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿ˜ณ.. ํ•˜์ง€๋งŒ ์„ค๋ช…ํ•˜๋Š” ์ข‹์€ ์†”๋ฃจ์…˜์—์„œ ์ƒํƒœ ๊ฐ’์€ ์–ด๋””์— ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด ์œ„์ ฏ ๊ฐ„์— ์‰ฝ๊ฒŒ ๊ตฌ์„ฑ ๋ฐ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ž˜ํ•‘/์บก์Šํ™”ํ•˜๋Š” ์ƒํƒœ ๋น„์ฆˆ๋‹ˆ์Šค ๋…ผ๋ฆฌ ๋ฐ ์ˆ˜๋ช… ์ด๋ฒคํŠธ ๋…ผ๋ฆฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ์ข‹์€ ์†”๋ฃจ์…˜์˜ ๊ธฐ๋Šฅ๊ณผ ์ด์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

์—ฌ๊ธฐ์— ์•ฝ๊ฐ„ ๋ผ์–ด๋“ค์–ด ์ด ํ† ๋ก ์˜ ์˜ˆ์˜์— ๋Œ€ํ•œ ์–ธ๊ธ‰์ด ์žˆ์Œ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์—ฌ๊ธฐ ์žˆ๋Š” ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋ฌด๋ก€ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฆ‰, ์ด๊ฒƒ์ด ์‚ฌ๋žŒ๋“ค์ด ๋ชจ๋“ ๋ฉด์—์„œ ๊นŠ์ด ๊ด€์‹ฌ์„ ๊ฐ–๋Š” ์ฃผ์ œ๋ผ๋Š” ์ ์€ ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

  • @rrousselGit ์€ StackOverflow ๋ฐ package:provider ๋ฌธ์ œ ์ถ”์ ๊ธฐ์˜ ์ƒํƒœ ๊ด€๋ฆฌ์— ๋Œ€ํ•œ ์ดˆ๋ณด์ž ์งˆ๋ฌธ์— ์ˆ˜๋…„ ๋™์•ˆ ๋‹ต๋ณ€ํ•ด ์™”์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด ํŒŒ์ด์–ดํ˜ธ์Šค ์ค‘ ํ›„์ž๋งŒ ๋”ฐ๋ฅด๊ณ  ์žˆ๊ณ , ๋ ˆ๋ฏธ์˜ ๊ทผ๋ฉด์„ฑ๊ณผ ์ธ๋‚ด์‹ฌ์— ๊ฒฝ์˜๋ฅผ ํ‘œํ•  ์ˆ˜๋ฐ–์— ์—†๋‹ค.
  • @Hixie ์™€ Flutter ํŒ€์˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์€ Flutter์˜ API, ์•ˆ์ •์„ฑ, ํ‘œ๋ฉด, ์œ ์ง€ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ์„ฑ ๋ฐ ๊ฐ€๋…์„ฑ์— ๊นŠ์€ ๊ด€์‹ฌ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Flutter์˜ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜์ด ์˜ค๋Š˜๋‚ ๊ณผ ๊ฐ™์€ ์œ„์น˜์— ์žˆ๊ฒŒ ๋œ ๊ฒƒ์€ ์ด ๋•๋ถ„์ž…๋‹ˆ๋‹ค.
  • Flutter ๊ฐœ๋ฐœ์ž๋Š” ๊ฐœ๋ฐœ ์‹œ๊ฐ„์˜ ์ƒ๋‹น ๋ถ€๋ถ„์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒํƒœ ๊ด€๋ฆฌ์— ๊นŠ์€ ๊ด€์‹ฌ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํ† ๋ก ์˜ ๋ชจ๋“  ๋‹น์‚ฌ์ž๊ฐ€ ์ž์‹ ์ด ํ•˜๋Š” ์ผ์— ๋Œ€ํ•ด ๋…ผ์Ÿํ•  ์ถฉ๋ถ„ํ•œ ์ด์œ ๊ฐ€ ์žˆ์Œ์ด ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ๊ฒƒ๋„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํ† ๋ก ์ด ์—ฌ๊ธฐ์—์„œ๋“  ๋‹ค๋ฅธ ํ˜•์‹์œผ๋กœ๋“  ๊ณ„์†๋œ๋‹ค๋ฉด ๊ธฐ์  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ณต์‹ ๋ฌธ์„œ์™€ ๊ฐ™์ด ์–ด๋–ค ์‹์œผ๋กœ๋“  ๋„์›€์ด ๋œ๋‹ค๋ฉด ์•Œ๋ ค์ฃผ์„ธ์š”.

๋ฐ˜๋ฉด์— ์‚ฌ๋žŒ๋“ค์ด ์—ฌ๊ธฐ ํ† ๋ก ์ด ์†์— ์žกํžˆ์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋ฉด ์ž ์‹œ ๋ฉˆ์ถ”๊ณ  ๋” ๋‚˜์€ ์˜์‚ฌ ์†Œํ†ต ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ๋ด…์‹œ๋‹ค.

(๋”ฐ๋กœ ์ด ํ† ๋ก ์— ์ฐธ์—ฌ ํ•ด์ฃผ์‹  @gaearon ์—๊ฒŒ ์ „ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค . ์ด ์ ์—์„œ React์˜ ๊ฒฝํ—˜์€ ๋งค์šฐ ์†Œ์ค‘ํ•ฉ๋‹ˆ๋‹ค.)

@emanuel-lundman

๊ทธ๋Ÿฌ๋‚˜ ๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ์ข‹์€ ์†”๋ฃจ์…˜์—์„œ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด ์œ„์ ฏ ๊ฐ„์— ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•˜๊ณ  ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ž˜ํ•‘/์บก์Šํ™”ํ•˜๋Š” ์ƒํƒœ ๊ฐ’, ์ƒํƒœ ๋น„์ฆˆ๋‹ˆ์Šค ๋…ผ๋ฆฌ ๋ฐ ์ˆ˜๋ช… ์ด๋ฒคํŠธ ๋…ผ๋ฆฌ๊ฐ€ ์–ด๋””์— ์žˆ์Šต๋‹ˆ๊นŒ? ์ข‹์€ ์†”๋ฃจ์…˜์˜ ๊ธฐ๋Šฅ๊ณผ ์ด์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

์ œ๊ฐ€ ์ž˜ ๋ชฐ๋ผ์„œ ์ž์„ธํžˆ ๋ง์”€์„ ๋“œ๋ฆฌ์ง€ ๋ชปํ•ด์„œ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. :-)

@escamoteur

fetchuser ์˜ˆ์ œ๊ฐ€ ์ด์ƒ์ ์ธ ์˜ˆ์ œ๊ฐ€ ์•„๋‹ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ useStream, useAnimstion ๋˜๋Š” useStreamCinroller๋Š” ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ํ›จ์”ฌ ๋” ๊น”๋”ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  dudChangeDependencues๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์˜ ์–ด๋ ค์›€ ์ค‘ ํ•˜๋‚˜๋Š” ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๊ณ  ๋ถ„์„ํ•  ๋•Œ ๋ฌธ์ œ๋ฅผ ์‹ค์ œ ๋ฌธ์ œ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์œผ๋กœ ์น˜๋ถ€ํ•˜๊ณ  ์ƒˆ๋กœ์šด ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๋“ฑ์˜ "๊ณจ๋Œ€ ์ด๋™"์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์œ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๋ฌธ์ œ์˜ ์‹ค์ œ ์˜ˆ๊ฐ€ ์žˆ๋Š” ๋ฐ๋ชจ Flutter ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ๊ณผ ๊ฐ™์ด ์„ค๋ช…์„ ์œ„ํ•ด ์ง€๋‚˜์น˜๊ฒŒ ๋‹จ์ˆœํ™”๋˜์ง€ ์•Š์€ ๋ช‡ ๊ฐ€์ง€ ์ •์‹ ์˜ˆ๋ฅผ ์ œ์‹œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ Hooks ๋ฐ ๊ธฐํƒ€ ์ œ์•ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ๋‹ค์‹œ ๊ตฌํ˜„ํ•˜๊ณ  ๊ตฌ์ฒด์ ์ธ ์šฉ์–ด๋กœ ์„œ๋กœ์— ๋Œ€ํ•ด ์‹ค์ œ๋กœ ํ‰๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ •ํ™•ํžˆ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” ์ง์ ‘ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ด๋ฏ€๋กœ Hooks๋ฅผ ์˜นํ˜ธํ•˜๋Š” ์‚ฌ๋žŒ์ด ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค.)

์‹ค์ œ๋กœ ์œ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๋ช‡ ๊ฐ€์ง€ ์ •์‹ ์˜ˆ๋ฅผ ์ œ์‹œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์„ค๋ช…์„ ์œ„ํ•ด ์ง€๋‚˜์น˜๊ฒŒ ๋‹จ์ˆœํ™”๋˜์ง€ ์•Š์€ ๋ฌธ์ œ์˜ ์‹ค์ œ ์˜ˆ๊ฐ€ ์žˆ๋Š” ๋ฐ๋ชจ Flutter ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

๋‚ด๊ฐ€ ์—ฌ๊ธฐ์— ์ œ์‹œํ•œ ์˜ˆ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ? https://github.com/flutter/flutter/issues/51752#issuecomment -669626522

์ด๊ฒƒ์€ ์‹ค์ œ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์ž…๋‹ˆ๋‹ค.

์ข‹์€ ์‹œ์ž‘์ด ๋  ๊ฒƒ ๊ฐ™์•„์š”. ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ฒ„์ „๊ณผ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ„์ „์œผ๋กœ ๋…๋ฆฝ ์‹คํ–‰ํ˜• ์•ฑ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ์ƒํƒœ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์•ฑ์ด ์•„๋‹Œ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ์˜๋ฏธํ–ˆ์Šต๋‹ˆ๋‹ค.

"๋ฐ๋ชจ Flutter ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ" ์•„์ด๋””์–ด์˜ ๋ฌธ์ œ ์ค‘ ํ•˜๋‚˜๋Š” ์ด ์Šค๋ ˆ๋“œ์—์„œ ๋งŒ๋“  ์˜ˆ์ œ๊ฐ€ ๋งค์šฐ ์‹ค์ œ์ ์ด๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ๋“ค์€ ์ง€๋‚˜์น˜๊ฒŒ ๋‹จ์ˆœํ™”๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
ํ›„ํฌ์˜ ์ฃผ์š” ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋””๋ฐ”์šด์Šค, ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ, ๊ตฌ๋… ๋˜๋Š” ์•”์‹œ์  ๋ถ€์ž‘์šฉ๊ณผ ๊ฐ™์€ ๋งˆ์ดํฌ๋กœ ์ƒํƒœ๋ฅผ ์ธ์ˆ˜๋ถ„ํ•ดํ•˜์—ฌ ๋” ์œ ์šฉํ•œ ๋กœ์ง์„ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํ•จ๊ป˜ ๊ฒฐํ•ฉ๋ฉ๋‹ˆ๋‹ค.

https://marvel.riverpod.dev/#/ ์™€ ๊ฐ™์€ Riverpod์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์†Œ์Šค ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. https://github.com/rrousselGit/river_pod/tree/master/examples/marvel/lib
๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์ง€๊ธˆ๊นŒ์ง€ ์–ธ๊ธ‰๋œ ๊ฒƒ๊ณผ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@Hixie

์ด๊ฒƒ์ด ์™œ ๋ฌธ์ œ์ธ์ง€ ์ดํ•ดํ•˜๊ธฐ๊ฐ€ ์ •๋ง ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์ €๋Š” Flutter ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŽ์ด ์ž‘์„ฑํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ํฐ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๊นŒ? ์ตœ์•…์˜ ๊ฒฝ์šฐ์—๋„ ์†์„ฑ์„ ์„ ์–ธํ•˜๊ณ , ์ดˆ๊ธฐํ™”ํ•˜๊ณ , ํ๊ธฐํ•˜๊ณ , ๋””๋ฒ„๊ทธ ๋ฐ์ดํ„ฐ์— ๋ณด๊ณ ํ•˜๋Š” ๋ฐ 4์ค„์ด ์†Œ์š”๋ฉ๋‹ˆ๋‹ค(์‹ค์ œ๋กœ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ์™€ ๋™์ผํ•œ ์ค„์—์„œ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ์ ์Šต๋‹ˆ๋‹ค. ์•ฑ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋””๋ฒ„๊ทธ ์†์„ฑ์— ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ์ด๋Ÿฌํ•œ ๊ฐ์ฒด ์ค‘ ๋‹ค์ˆ˜๋Š” ํ๊ธฐํ•ด์•ผ ํ•˜๋Š” ์ƒํƒœ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ฐ™์€ ๋ฐฐ์— ์žˆ๋‹ค.
์ €๋„ ์—ฌ๊ธฐ์— ์„ค๋ช…๋œ ๋ฌธ์ œ๋ฅผ ์ž˜ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ์ ์„ ์ธ์ •ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์žฌ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์žˆ๋Š” "์ƒํƒœ ๋…ผ๋ฆฌ"๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋งŽ์€ ์ƒํƒœ ์ €์žฅ ์–‘์‹ ์œ„์ ฏ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ์ผ๋ถ€๋Š” ์ˆ˜์‹ญ ๊ฐœ์˜ ์–‘์‹ ํ•„๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ํ…์ŠคํŠธ ์ปจํŠธ๋กค๋Ÿฌ์™€ ํฌ์ปค์Šค ๋…ธ๋“œ๋ฅผ ์ง์ ‘ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. statelesswidget์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ์—์„œ ์ƒ์„ฑํ•˜๊ณ  ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. ๊ฝค ์ง€๋ฃจํ•˜์ง€๋งŒ ๋™์ผํ•œ ์–‘์˜ ์ปจํŠธ๋กค๋Ÿฌ/focusNode ๋˜๋Š” ๋™์ผํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์œ„์ ฏ์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค ์‚ฌ์ด์˜ ์œ ์ผํ•œ ๊ณตํ†ต์ ์€ ์ƒํƒœ๊ฐ€ ์žˆ๊ณ  ํ˜•์‹์ด ๋œ๋‹ค๋Š” ์ผ๋ฐ˜์ ์ธ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ํŒจํ„ด์ด๋ผ๊ณ  ํ•ด์„œ ์ฝ”๋“œ๊ฐ€ ๋ฐ˜๋ณต๋˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.
๋‚ด ์ฝ”๋“œ์˜ ๋งŽ์€ ๋ถ€๋ถ„์—์„œ ๋ฐฐ์—ด์„ ๋ฐ˜๋ณตํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์•ฑ ๋ฐ˜๋ณต ์ฝ”๋“œ ์ „์ฒด์—์„œ "for(var thing in things)"๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ €๋Š” ๋ผ์ดํ”„์‚ฌ์ดํด API์˜ ๋‹จ์ˆœํ•จ์—์„œ ๋น„๋กฏ๋œ StatefulWidget์˜ ํž˜์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์•ฑ์˜ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„๊ณผ ๋ถ„๋ฆฌํ•˜์—ฌ ์ˆ˜ํ–‰ํ•˜๋Š” StatefulWidget์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ์œ„์ ฏ์˜ "์ƒํƒœ"๋Š” ํ•ญ์ƒ ์ž์ฒด์ ์œผ๋กœ ๋น„๊ณต๊ฐœ์ด๋ฏ€๋กœ ๋‚ด ์œ„์ ฏ์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์œผ๋ฉฐ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ๋„ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ๊ฐ€์ ธ์˜จ ์˜ˆ์ œ์™€ ๊ด€๋ จํ•˜์—ฌ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ท€ํ•˜์˜ ์š”์ ๊ณผ ์–ด๋Š ์ •๋„ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

  • ์ •ํ™•ํžˆ ๋™์ผํ•œ "์ƒํƒœ ๋…ผ๋ฆฌ"๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ์ž˜๋ชป๋œ ๊ฒƒ์œผ๋กœ ๋ณด์ด๋ฉฐ ์œ„์ ฏ์ด ์ž์ฒด์ ์œผ๋กœ ํฌํ•จ๋œ๋‹ค๋Š” ์•„์ด๋””์–ด์— ๋ฐ˜๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์‹œ, ๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์ผ๋ฐ˜์ ์ธ "์ƒํƒœ ๋…ผ๋ฆฌ"๋ฅผ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ•ฉ๋‹ˆ๋‹ค.
  • ํ›„ํฌ๋Š” ์ผ๋ฐ˜ ๋‹คํŠธ ๋ฐ ๊ธฐ๋ณธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐœ๋…(์˜ˆ: ํ•จ์ˆ˜)์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • ๋ฌธ์ œ๋Š” "์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ „์—ญ ์ƒํƒœ"๋ฅผ ์„ ํ˜ธํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š” ํŠน์ • ์Šคํƒ€์ผ์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ๊ด€๋ จ์ด ์žˆ๊ฑฐ๋‚˜ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.
  • ๋ช‡ ์ค„์˜ ์ฝ”๋“œ๋ฅผ ์ถ”์ƒํ™”ํ•˜๋ฉด "์กฐ๊ธฐ ์ฝ”๋“œ ์ตœ์ ํ™”" ๋ƒ„์ƒˆ๊ฐ€ ๋‚˜๋ฉฐ ํ”„๋ ˆ์ž„์›Œํฌ ๋ฐ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๊ฑฐ์˜ ๊ด€๋ จ์ด ์—†๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ณต์žก์„ฑ์ด ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๊ฐ€๋…์„ฑ์ด ํ˜„์ €ํžˆ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

  • 10๋‹จ๊ณ„์˜ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•„ํ„ฐ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด FilterBuilder ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ 12๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.
  • ํ•„ํ„ฐ ๋กœ์ง์€ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

    • ์‹ค์ˆ˜๋กœ timer ์ทจ์†Œํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • build ๋ฐฉ๋ฒ•์˜ ์ ˆ๋ฐ˜์€ ๋…์ž์—๊ฒŒ ์œ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Builders๋Š” ์ค‘์š”ํ•œ ๊ฒƒ์—์„œ ์šฐ๋ฆฌ๋ฅผ ์‚ฐ๋งŒํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ด„ํ˜ธ๊ฐ€ ์—†์–ด์„œ ์ฝ”๋“œ๊ฐ€ ์ปดํŒŒ์ผ๋˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ 5๋ถ„์„ ๋‚ญ๋น„ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ท€ํ•˜์˜ ์˜ˆ๋Š” Flutter์˜ StatelessWidget ๋ฐ State ์ˆ˜๋ช… ์ฃผ๊ธฐ API์˜ ์‹ค์ œ ๋ฌธ์ œ๋ผ๊ธฐ๋ณด๋‹ค๋Š” ๊ณต๊ธ‰์ž๊ฐ€ ์–ผ๋งˆ๋‚˜ ์žฅํ™ฉํ•œ์ง€, ๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“  ๊ฒƒ์— ๋Œ€ํ•ด InheritedWidgets๋ฅผ ๋‚จ์šฉํ•˜๋Š” ๊ฒƒ์ด ์™œ ๋‚˜์œ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@rrousselGit ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์œ„์—์„œ ์ œ๊ฐ€ ์ œ์•ˆํ•œ ๊ฒƒ์€ ๊ตฌ์ฒด์ ์œผ๋กœ ํ˜„์‹ค์ ์ด๊ณ  ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐ”๋‹๋ผ Flutter ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ(StatefulWidget ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ)์„ ์ƒ์„ฑํ•˜์—ฌ ์‹ค์ œ ์ „์ฒด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. "fetchUser" ์˜ˆ์ œ์™€ ๊ฐ™์ด ์—ฌ๊ธฐ์—์„œ ๋…ผ์˜ํ•œ ๊ตฌ์ฒด์ ์ธ ์˜ˆ์ œ๋Š” ํ•ญ์ƒ "์ด๋Ÿฐ ๊ฒฝ์šฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ  ๊ฐ„๋‹จํ•˜๊ณ  Hooks๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค"๋ผ๋Š” ๋ผ์ธ์— ๋”ฐ๋ฅธ ํ† ๋ก ์œผ๋กœ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค. "๊ธ€์Ž„์š”, ๊ทธ๊ฑด ์ง€๋‚˜์น˜๊ฒŒ ๋‹จ์ˆœํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ์„ธ๊ณ„์—์„œ๋Š” Hooks๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค." ๊ทธ๋ž˜์„œ ์ œ ์š”์ ์€ ์‹ค์ œ๋กœ Hooks๊ฐ€ ํ•„์š”ํ•˜๊ณ  ์ง€๋‚˜์น˜๊ฒŒ ๋‹จ์ˆœํ™”๋˜์ง€ ์•Š์€ ์‹ค์ œ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์˜ ์–ด๋ ค์›€์„ ๋ณด์—ฌ์คŒ์œผ๋กœ์จ ์ƒˆ๋กœ์šด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. , ๋˜๋Š” ์ƒˆ ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ, ํ›„์ž์˜ ๊ฒฝ์šฐ Hooks์™€ ๊ฐ™์€ ๋ชจ์–‘์ด์–ด์•ผ ํ•˜๋Š”์ง€ ๋˜๋Š” ๋” ๋‚˜์€ ์†”๋ฃจ์…˜์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€.

๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์žฌ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์žˆ๋Š” "์ƒํƒœ ๋…ผ๋ฆฌ"๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿด ์ˆ˜ ์žˆ์ง€
์ƒํƒœ ๋…ผ๋ฆฌ์™€ ํ‰ํ–‰์„ ์ด๋ฃจ๋Š” ๊ฒƒ์€ UI ๋…ผ๋ฆฌ์™€ ์œ„์ ฏ์ด ํ…Œ์ด๋ธ”์— ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์ ์œผ๋กœ ์œ„์ ฏ ๋ ˆ์ด์–ด๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ƒํ™ฉ์—์„œ ๋‚จ์€ ๊ฒƒ์€ RenderObjects์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์šฐ๋ฆฌ๋Š” ์ตœ์†Œํ•œ์˜ ์นด์šดํ„ฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

var counter = 0;

final counterLabel = RenderParagraph(
  TextSpan(text: '$counter'),
  textDirection: TextDirection.ltr,
);

final button = RenderPointerListener(
  onPointerUp: (_) {
    counter++;
    counterLabel.text = TextSpan(text: '$counter');
  },
  child: counterLabel,
);

๊ทธ๊ฒƒ์ด ๋ฐ˜๋“œ์‹œ ๋ณต์žกํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. counterLabel ๋ Œ๋”๋ง์— ์ค‘๋ณต ํ•ญ๋ชฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class _CounterState exends State {
  int counter = 0;

  Widget build(context ) {
    return GestureDetector(
      onTap: () => setState(() => counter++);
      child: Text('$counter'),
    );
  }
}

์ด๊ฒƒ์ด ํ•œ ์œ ์ผํ•œ ๊ฒƒ์€ Text ๋…ผ๋ฆฌ๋ฅผ ์„ ์–ธ์ ์œผ๋กœ ๋งŒ๋“ค์–ด ์ธ์ˆ˜๋ถ„ํ•ดํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ตœ์†Œํ•œ์˜ ๋ณ€ํ™”์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋Œ€๊ทœ๋ชจ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ์ด๋Š” ์ƒ๋‹นํ•œ ๋‹จ์ˆœํ™”์ž…๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ๋˜‘๊ฐ™์€ ์ผ์„ ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ Text ๋Œ€์‹  ์ƒํƒœ ๋…ผ๋ฆฌ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ํ›„ํฌ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋ฆฌ์Šค๋„ˆ, ๋””๋ฐ”์šด์‹ฑ, HTTP ์š”์ฒญ ๋งŒ๋“ค๊ธฐ ๋“ฑ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.


๊ท€ํ•˜์˜ ์˜ˆ๋Š” Flutter์˜ StatelessWidget ๋ฐ State ์ˆ˜๋ช… ์ฃผ๊ธฐ API์˜ ์‹ค์ œ ๋ฌธ์ œ๋ผ๊ธฐ๋ณด๋‹ค๋Š” ๊ณต๊ธ‰์ž๊ฐ€ ์–ผ๋งˆ๋‚˜ ์žฅํ™ฉํ•œ์ง€, ๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“  ๊ฒƒ์— ๋Œ€ํ•ด InheritedWidgets๋ฅผ ๋‚จ์šฉํ•˜๋Š” ๊ฒƒ์ด ์™œ ๋‚˜์œ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๊ณต๊ธ‰์ž์™€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค(์ด ์ฝ”๋“œ๋Š” ๊ฒฐ๊ตญ ๊ณต๊ธ‰์ž๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค).
์–ด๋–ค ๊ฒฝ์šฐ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ œ๊ณต์ž๋Š” ๋” ๋‚˜์€์ด context.watch ๋Œ€์‹  Consumer .

ํ‘œ์ค€ ์†”๋ฃจ์…˜์€ Consumer ๋ฅผ ValueListenableBuilder ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๋˜‘๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

@Hixie ์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ Flutter๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์˜ ํšจ์œจ์„ฑ์„ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€๋ฅผ ๋‚˜๋ž€ํžˆ ๋น„๊ตํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋˜ํ•œ ํ›„ํฌ๊ฐ€ ๋” ๋‚˜์€์ง€ ์•„๋‹Œ์ง€ ๋˜๋Š” ๋ฐ”๋‹๋ผ ์•ฑ์ด ์ด ์„ธ ๋ฒˆ์งธ ์†”๋ฃจ์…˜์œผ๋กœ ๋นŒ๋“œ๋œ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์ด ๋” ๋‚˜์€์ง€ ์—ฌ๋ถ€๋ฅผ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ํ™•์‹ ์‹œํ‚ค๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฐ”๋‹๋ผ ์•ฑ ๊ฐœ๋…์€ TodoMVC ์™€ ๊ฐ™์€ ๊ฒƒ๋“ค์ด ๋‹ค์–‘ํ•œ ํ”„๋ก ํŠธ ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐ„์˜ ์ฐจ์ด์ ์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ๊ณผ ํ•จ๊ป˜ ํ•œ๋™์•ˆ ์‚ฌ์šฉ๋˜์–ด ์™”๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ˜๋“œ์‹œ ์ƒˆ๋กœ์šด ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ ์•ฑ์„ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์„ ๋“œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@satvikpendem
๊ธฐ๊บผ์ด ๋„์™€๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.
flutter_hooks ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์˜ ์˜ˆ์ œ ์•ฑ์€ ์•„๋งˆ๋„ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋‹ค๋ฅธ ํ›„ํฌ์™€ ์ด๋“ค์ด ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“œ๋Š”/๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ฃผ๊ณ  ์ข‹์€ ์ถœ๋ฐœ์ ์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋˜ํ•œ ์šฐ๋ฆฌ๊ฐ€ ์ด ํ˜ธ์— ์ œ์‹œ๋œ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์™€ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์—…๋ฐ์ดํŠธ: ์ฝ”๋“œ๋Š” https://github.com/TimWhiting/local_widget_state_approaches์— ์žˆ์Šต๋‹ˆ๋‹ค.
์ €์žฅ์†Œ์˜ ์ ์ ˆํ•œ ์ด๋ฆ„์ด ํ™•์‹คํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ทธ๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ๋ผ๊ณ  ๊ฐ€์ •ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์ƒํƒœ ์ €์žฅ ๋ฐ ํ›„ํฌ์—์„œ ๊ธฐ๋ณธ ์นด์šดํ„ฐ ์•ฑ์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋Š˜ ๋ฐค ์‹œ๊ฐ„์ด ๋งŽ์ง€๋Š” ์•Š์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์„ ๋” ์ž˜ ์„ค๋ช…ํ•˜๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋” ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ์—ฌํ•˜๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ์€ ์•ก์„ธ์Šค ๊ถŒํ•œ์„ ์š”์ฒญํ•˜์‹ญ์‹œ์˜ค.

"fetchUser" ์˜ˆ์ œ์™€ ๊ฐ™์ด ์—ฌ๊ธฐ์—์„œ ๋…ผ์˜ํ•œ ๊ตฌ์ฒด์ ์ธ ์˜ˆ์ œ๋Š” ํ•ญ์ƒ "์ด๋Ÿฐ ๊ฒฝ์šฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ  ๊ฐ„๋‹จํ•˜๊ณ  Hooks๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค"๋ผ๋Š” ๋ผ์ธ์— ๋”ฐ๋ฅธ ํ† ๋ก ์œผ๋กœ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค. "๊ธ€์Ž„์š”, ๊ทธ๊ฑด ์ง€๋‚˜์น˜๊ฒŒ ๋‹จ์ˆœํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ์„ธ๊ณ„์—์„œ๋Š” Hooks๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค."

๋‚˜๋Š” ๋™์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋‚˜๋Š” "์ด๋Ÿฐ ๊ฒฝ์šฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค"๋Š” ๊ฒƒ์„ ๋ณธ ์ ์ด ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ณ  ๊ฒฐ๊ณผ ์ฝ”๋“œ๊ฐ€ ํ›„ํฌ ๋ณ€ํ˜•๋ณด๋‹ค ๋‚ซ๋‹ค๋Š” ๋ฐ ๋™์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ์š”์ ์€ ์šฐ๋ฆฌ๊ฐ€ ์ผ์„ ๋‹ค๋ฅด๊ฒŒ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ฒฐ๊ณผ ์ฝ”๋“œ๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ๊ณ  ๊ฐ€๋…์„ฑ์ด ๋‚ฎ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ fetchUser ์—๋„ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ๋˜‘๊ฐ™์€ ์ผ์„ ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ Text ๋Œ€์‹  ์ƒํƒœ ๋…ผ๋ฆฌ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ํ›„ํฌ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋ฆฌ์Šค๋„ˆ, ๋””๋ฐ”์šด์‹ฑ, HTTP ์š”์ฒญ ๋งŒ๋“ค๊ธฐ ๋“ฑ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

์•„๋‹ˆ์š”, ์ €๋Š” ์—ฌ์ „ํžˆ ์ด ์ผ๋ฐ˜์ ์ธ ์ƒํƒœ ๋…ผ๋ฆฌ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ๋ง์€ "initState/didUpdateDependency" ๋ฉ”์†Œ๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ฝ๋Š” ๋งŽ์€ ์œ„์ ฏ์ด ์žˆ์ง€๋งŒ ์ •ํ™•ํžˆ ๋™์ผํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“œ๋Š” ๋‘ ์œ„์ ฏ์„ ์ฐพ์„ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ "๋…ผ๋ฆฌ"๊ฐ€ ๋™์ผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

HTTP ์š”์ฒญ์„ ๋งŒ๋“œ๋Š” ์˜ˆ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์œ„์ ฏ ์ค‘ ์ผ๋ถ€๊ฐ€ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์„œ๋น„์Šค ํด๋ž˜์Šค ์–ด๋”˜๊ฐ€์— "makeHTTPRequest(url, paramters)"๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋Œ€์‹  ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด ๊ฒฝ์šฐ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๊ณผ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฆ…๋‹ˆ๊นŒ?

์ฒญ์ทจ์ž. ๊ฐ™์€ ๊ฒƒ์„ ๋“ฃ๋Š” ์œ„์ ฏ์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ฐ ์œ„์ ฏ์€ ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ์„ ๊ตฌ๋…ํ•˜๊ณ  ๊ตฌ๋…์„ ์ทจ์†Œํ•  ์ฑ…์ž„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๊ตฌ๋ฌธ์ƒ์˜ ์„คํƒ•์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ๋‚ด ์œ„์ ฏ์€ ๋™์ผํ•œ ๊ฐ์ฒด ์กฐํ•ฉ์„ ์ˆ˜์‹ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ›„ํฌ๋Š” ์–ด๋–ป๊ฒŒ๋“  "๋งค๊ฐœ๋ณ€์ˆ˜ํ™”"๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ํ›„ํฌ๋Š” ํ‰๋ฒ”ํ•œ ์ด์ „ ํ•จ์ˆ˜์™€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ๊ฐ€์š”?


์ด๊ฒƒ์€ ๊ณต๊ธ‰์ž์™€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค(์ด ์ฝ”๋“œ๋Š” ๊ฒฐ๊ตญ ๊ณต๊ธ‰์ž๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค).
์–ด๋–ค ๊ฒฝ์šฐ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ œ๊ณต์ž๋Š” ๋” ๋‚˜์€์ด context.watch ๋Œ€์‹  Consumer .

๋ญ? "ChatScreen" HookWidget์ด ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๋ฐ˜๋ก€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<strong i="19">@override</strong>
  Widget build(BuildContext context) {
    return Consumer<Auth>(
      provider: authProvider,
      builder: (context, auth, child) {
        return Consumer<int>(
          provider: selectedChatProvider,
          builder: (context, chatId, child) {

์ด๊ฒƒ์€ ๊ณต๊ธ‰์ž์™€ ์–ด๋–ป๊ฒŒ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๊นŒ? ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œ์š”. ๋‚˜๋Š” Provider์˜ ์ „๋ฌธ๊ฐ€๋Š” ์•„๋‹ˆ์ง€๋งŒ ์ด๊ฒƒ์€ ํ™•์‹คํžˆ Provider๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค.

์ €๋Š” ์ด ๋ฌธ์ œ๊ฐ€ ๋ณต์žกํ•œ ์ƒํƒœ์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋Š” ์‚ฌ์‹ค์„ ๊ฐ•์กฐํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.
์ „์ฒด ์ฝ”๋“œ๋ฒ ์ด์Šค์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์€ ์ฆ๋ถ„์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์ œ๊ณต๋œ ์˜ˆ์ œ์˜ ๊ฐ€์น˜์— ๋™์˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋Œ€ํ™”์— ์•„๋ฌด ๊ฒƒ๋„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. StatefulWidget์œผ๋กœ ํ•  ์ˆ˜ ์—†๋Š” ํ›„ํฌ๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋Œ€์‹  ImplicitFetcher ์™€ ๊ฐ™์€ ๋งˆ์ดํฌ๋กœ ์Šค๋‹ˆํŽซ์„ ๋‚˜๋ž€ํžˆ ๋น„๊ตํ•˜๊ณ  ์ธก์ • ๊ฐ€๋Šฅํ•œ ๋ฉ”ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ด๋–ค ์ฝ”๋“œ๊ฐ€ ๋” ๋‚˜์€์ง€ _๊ฐ๊ด€์ ์œผ๋กœ_ ๊ฒฐ์ •ํ•˜๊ณ  ๋‹ค์–‘ํ•œ ์ž‘์€ ์Šค๋‹ˆํŽซ์— ๋Œ€ํ•ด ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.


์ด๊ฒƒ์€ ๊ณต๊ธ‰์ž์™€ ์–ด๋–ป๊ฒŒ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๊นŒ? ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œ์š”. ๋‚˜๋Š” Provider์˜ ์ „๋ฌธ๊ฐ€๋Š” ์•„๋‹ˆ์ง€๋งŒ ์ด๊ฒƒ์€ ํ™•์‹คํžˆ Provider๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค.

์ด ์ฝ”๋“œ๋Š” Provider์—์„œ ์˜จ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ InheritedWidgets๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์—์„œ ์˜จ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ณต๊ธ‰์ž์˜ Consumer ์— provider ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ œ๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด Consumer -> ValueListenableBuilder/StreamBuilder/BlocBuilder/Observer/...

"initState/didUpdateDependency" ๋ฉ”์„œ๋“œ์— ์žˆ์ง€๋งŒ ์ •ํ™•ํžˆ ๋™์ผํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“œ๋Š” ๋‘ ๊ฐœ์˜ ์œ„์ ฏ์„ ์ฐพ์„ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ "๋…ผ๋ฆฌ"๊ฐ€ ๋™์ผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์žฌ์‚ฌ์šฉํ•˜๋ ค๋Š” ์ƒํƒœ ๋…ผ๋ฆฌ๋Š” "์ฟผ๋ฆฌ ์ž‘์„ฑ"์ด ์•„๋‹ˆ๋ผ "x๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ฌด์—‡์ธ๊ฐ€ ์ˆ˜ํ–‰"์ž…๋‹ˆ๋‹ค. "๋ฌด์–ธ๊ฐ€๋ฅผ ํ•˜๋ผ"๋Š” ๋ณ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ "x๊ฐ€ ๋ณ€ํ•  ๋•Œ"๋Š” ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค

๊ตฌ์ฒด์ ์ธ ์˜ˆ:
ID๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์œ„์ ฏ์ด HTTP ์š”์ฒญ์„ ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋˜ํ•œ package:async ์˜ CancelableOperation์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด๋ฅ˜ ์ค‘์ธ ์š”์ฒญ์„ ์ทจ์†Œํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ์ •ํ™•ํžˆ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋Š” ๋‘ ๊ฐœ์˜ ์œ„์ ฏ์ด ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ HTTP ์š”์ฒญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๊ฒฐ๊ตญ, ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:

CancelableOperation<User> pendingUserRequest;

initState() {
  pendingUserRequest = fetchUser(widget.userId);
}

didUpdateWidget(oldWidget) {
  if (widget.userId != oldWidget.userId) {
      pendingUserRequest.cancel();
      pendingUserRequest = fetchUser(widget.userId);
  }
}

dispose() {
  pendingUserRequest.cancel();
}

๋Œ€:

CancelableOperation<Message> pendingMessageRequest;

initState() {
  pendingMessageRequest = fetchMessage(widget.messageId);
}

didUpdateWidget(oldWidget) {
  if (widget.userId != oldWidget.messageId) {
      pendingMessageRequest.cancel();
      pendingMessageRequest = fetchMessage(widget.messageId);
      message = pendingMessageRequest.value;
  }
}

dispose() {
  pendingMessageRequest.cancel();
}

์œ ์ผํ•œ ์ฐจ์ด์ ์€ fetchUser ๋ฅผ fetchMessage ๋ณ€๊ฒฝํ–ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋…ผ๋ฆฌ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด 100% ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๊ฒƒ์„ useUnaryCancelableOperation ํ›„ํฌ๋กœ ๋ถ„ํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋™์ผํ•œ ๋‘ ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋Œ€์‹  ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  Future<User> user = useUnaryCancelableOperation(userId, fetchUser);
}

VS

Widget build(context) {
  Future<Message> message = useUnaryCancelableOperation(messageId, fetchMessage);
}

์ด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์š”์ฒญ ๋ฐ ์ทจ์†Œ์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ๋…ผ๋ฆฌ๊ฐ€ ๊ณต์œ ๋ฉ๋‹ˆ๋‹ค. fetchUser vs fetchMessage ๋ผ๋Š” ์˜๋ฏธ ์žˆ๋Š” ์ฐจ์ด๋งŒ ๋‚จ์Šต๋‹ˆ๋‹ค.
์ด useUnaryCancelableOperation ์—์„œ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ ์ด์ œ ๋ชจ๋“  ์‚ฌ๋žŒ์ด ์•ฑ์—์„œ ์ด๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์ œ๊ณต๋œ ์˜ˆ์ œ์˜ ๊ฐ€์น˜์— ๋™์˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋Œ€ํ™”์— ์•„๋ฌด ๊ฒƒ๋„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. StatefulWidget์œผ๋กœ ํ•  ์ˆ˜ ์—†๋Š” ํ›„ํฌ๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋งŒ์•ฝ ๊ทธ๊ฒƒ์ด ์ •๋ง๋กœ ์‚ฌ์‹ค์ด๋ผ๋ฉด ์šฐ๋ฆฌ๋Š” ์ด ๋ฒ„๊ทธ๋ฅผ ๋‹ซ์•„์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ์—ฌ๊ธฐ์— ์ฃผ์–ด์ง„ ์˜ˆ๋ฅผ ๋…ผ์˜ํ–ˆ๊ณ  ๊ทธ๊ฒƒ๋“ค์€ ์„ค๋“๋ ฅ์ด ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ƒํ™ฉ์„ ๋” ์ž˜ ์ดํ•ดํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ด ๋ฒ„๊ทธ์˜ ์ด์ „ ์˜๊ฒฌ์—์„œ ์ด์ ์ด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์ˆ˜์ค€์— ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฌ๋ฏ€๋กœ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ์˜ˆ๋ฅผ ์—ฐ๊ตฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์œ ์ผํ•œ ์ฐจ์ด์ ์€ fetchUser ๋ฅผ fetchMessage ๋ณ€๊ฒฝํ–ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋…ผ๋ฆฌ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด 100% ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด ๊ฒƒ์€ ๋ฌด์—‡์ด๋ฉฐ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ์ถ”์ƒํ™” ๋ฐ ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ํด๋ž˜์Šค์— ์„ธ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ํ•„์š”๊ฐ€ ์—†๊ณ  ๋„ˆ๋ฌด ๊ณผ๋„ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ์–ด๋–ค ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ด๋ผ๊ณ  ํ•ด์„œ ์ƒˆ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์ด ๊ฒฝ์šฐ ๋ฐ˜๋ณต์ ์ธ ์ฝ”๋“œ๋ฅผ ์ค„์ด๋ ค๋ฉด StatefulWidget* ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜๊ณ  initstate/didUpdateWidget ๋ฉ”์„œ๋“œ๋ฅผ ๊ณตํ†ต ๋น„ํŠธ๋กœ ์žฌ์ •์˜ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๊ฒƒ์„ useUnaryCancelableOperation ํ›„ํฌ๋กœ ์ธ์ˆ˜๋ถ„ํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋™์ผํ•œ ๋‘ ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋Œ€์‹  ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  Future<User> user = useUnaryCancelableOperation(userId, fetchUser);
}

VS

Widget build(context) {
  Future<Message> message = useUnaryCancelableOperation(messageId, fetchMessage);
}

์ด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์š”์ฒญ ๋ฐ ์ทจ์†Œ์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ๋…ผ๋ฆฌ๊ฐ€ ๊ณต์œ ๋ฉ๋‹ˆ๋‹ค. fetchUser vs fetchMessage ๋ผ๋Š” ์˜๋ฏธ ์žˆ๋Š” ์ฐจ์ด๋งŒ ๋‚จ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
์ด useUnaryCancelableOperation ์—์„œ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๊ณ  ์ด์ œ ๋ชจ๋“  ์‚ฌ๋žŒ์ด ์•ฑ์—์„œ ์ด๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฏธ์•ˆํ•˜์ง€๋งŒ ๊ทธ๊ฑด ๋‚˜์—๊ฒŒ ํฐ ๊ฒฐ์ •์  ์•„๋‹ˆ์˜ค. ์ ์€ ์–‘์˜ ์ฝ”๋“œ ์ค‘๋ณต์„ฑ๋งŒ ์ ˆ์•ฝํ•œ๋‹ค๋Š” ์‚ฌ์‹ค ์™ธ์—๋„ ๊ฐœ๋…์ ์œผ๋กœ "initState" ๋ฐ "update" ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ์— ์†ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋นŒ๋“œ ๋ฉ”์„œ๋“œ๋กœ "์ธ์ˆ˜๋ถ„ํ•ด"ํ•˜๋Š” ๊ฒƒ์€ ํฐ ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

๋‚ด ๋นŒ๋“œ ๋ฐฉ๋ฒ•์ด ๋ ˆ์ด์•„์›ƒ๋งŒ ๋นŒ๋“œํ•˜๊ณ  ๋‹ค๋ฅธ ๊ฒƒ์€ ๋นŒ๋“œํ•˜์ง€ ์•Š์„ ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ์ข…์†์„ฑ์„ ์„ค์ •ํ•˜๊ณ  ํ•ด์ œํ•˜๋Š” ๊ฒƒ์€ ํ™•์‹คํžˆ ๋นŒ๋“œ ๋ฐฉ๋ฒ•์— ์†ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๋™์ผํ•œ ์œ ํ˜•์˜ ์ฝ”๋“œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๋‹ค์‹œ ์ž‘์„ฑํ•˜์—ฌ ๋‚ด ์œ„์ ฏ์ด ํ•˜๋Š” ์ผ์„ ๋ฏธ๋ž˜์˜ ๋‚˜์™€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋ช…์‹œ์ ์œผ๋กœ ํ‘œ์‹œํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ์— ๋ชจ๋“  ๊ฒƒ์„ ์ง‘์–ด๋„ฃ์ง€ ๋ง™์‹œ๋‹ค.

์ •๋ง ๊ทธ๋ ‡๋‹ค๋ฉด ์ด ๋ฒ„๊ทธ๋ฅผ ๋‹ซ์•„์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@Hixie ์ œ๋ฐœ ํ•˜์ง€๋งˆ. ์‚ฌ๋žŒ๋“ค์€ ์ด ๋ฌธ์ œ์— ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์•ฝ ๋ ˆ๋”ง์— ๋‹น์‹ ๊ณผ ํ•จ๊ป˜ ์ด์•ผ๊ธฐ ํ•œ ๊ฐ™์€ ์ผ์„ ํ•˜์ง€๋งŒ, SwiftUI์˜ ๋งฅ๋ฝ์—์„œ : https://github.com/szotp/SwiftUI_vs_Flutter

ํ›„ํฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์„ ์–ด๋–ป๊ฒŒ๋“  ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์€ ๋‹จ์ˆœํžˆ ์ƒ์šฉ๊ตฌ ์ž‘์„ฑ์„ ์‹ซ์–ดํ•ฉ๋‹ˆ๋‹ค. RAII ๋ฐ View์˜ ์˜๋ฏธ๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๋ฐ ์ต์ˆ™ํ•œ SwiftUI ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฐœ๋ฐœ์ž์—๊ฒŒ๋Š” ์ผํšŒ์šฉํ’ˆ์„ ์ˆ˜๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์˜ณ์ง€ ์•Š์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ €๋Š” flutter ํŒ€์ด ์ ์–ด๋„ ์ด๊ฒƒ์„ ๋ฌธ์ œ๋กœ ๋ณด๊ณ  ๋Œ€์•ˆ์ ์ธ ์†”๋ฃจ์…˜/๊ฐœ์„  ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ธฐ๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ๋นŒ๋“œ ๋ฐฉ๋ฒ•์ด ๋ ˆ์ด์•„์›ƒ๋งŒ ๋นŒ๋“œํ•˜๊ณ  ๋‹ค๋ฅธ ๊ฒƒ์€ ๋นŒ๋“œํ•˜์ง€ ์•Š์„ ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ์ข…์†์„ฑ์„ ์„ค์ •ํ•˜๊ณ  ํ•ด์ œํ•˜๋Š” ๊ฒƒ์€ ํ™•์‹คํžˆ ๋นŒ๋“œ ๋ฐฉ๋ฒ•์— ์†ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ค‘์š”ํ•œ ํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค. ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ๋Š” ์ˆœ์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ๋‚œ ์šฐ๋ฆฌ๊ฐ€ ์–ด๋ ค์›€ ์—†์ด ์žฅ์ ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž์–ด

์—ฌ๊ธฐ์— ๋” ๋งŽ์€ ์˜ˆ๋ฅผ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์ด ์ •๋ง ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์–ผ๊ตด์— ์„ ๋ช…ํ•ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ์— ์˜ํ•ด ํ•ด๊ฒฐ๋œ ๋ฌธ์ œ๋Š” ๊ฐ„๋‹จํ•˜๊ณ  ๋ช…๋ฐฑํ•˜๋ฉฐ ์ฝ”๋“œ๋ฅผ DRY๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์˜ ์ด์ ์€ ๋ช…๋ฐฑํ•œ ๊ฒƒ, ๋” ์ ์€ ์ฝ”๋“œ == ๋” ์ ์€ ๋ฒ„๊ทธ, ๋” ์‰ฌ์šด ์œ ์ง€ ๊ด€๋ฆฌ, ๋” ์ ์€ ๋ฒ„๊ทธ๊ฐ€ ์ˆจ๊ธธ ์žฅ์†Œ, ๋” ์ ์€ ์ค„์˜ ์ „์ฒด ๊ฐ€๋…์„ฑ ์ฆ๊ฐ€, ์ฃผ๋‹ˆ์–ด ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๋” ์ž˜ ์ ˆ์—ฐ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋งํ•˜๋Š” ๊ฒฝ์šฐ ๋งค๋ฒˆ 12๊ฐœ์˜ ๋‹ค๋ฅธ ๋ณด๊ธฐ์—์„œ 12๊ฐœ์˜ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์„ค์ • ๋ฐ ๋ถ„ํ•ดํ•˜์—ฌ dispose() ํ˜ธ์ถœ์„ ๋†“์น˜๊ฑฐ๋‚˜ ์ผ๋ถ€๋ฅผ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์„ ์—ด์–ด๋‘๋Š” ์•ฑ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฐฉ๋ฒ•. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ด๋ฅผ ์ˆ˜์‹ญ ๊ฐœ์˜ ๋‹ค๋ฅธ ์ƒํƒœ ์ €์žฅ ์ธ์Šคํ„ด์Šค์— ์ ์šฉํ•˜๋ฉด ์ˆ˜๋ฐฑ ๋˜๋Š” ์ˆ˜์ฒœ ๊ฐœ์˜ ๋ฌด์˜๋ฏธํ•œ ์ฝ”๋“œ ๋ผ์ธ์„ ์‰ฝ๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Flutter๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ง€์†์ ์œผ๋กœ ๋ฐ˜๋ณตํ•ด์•ผ ํ•˜๋Š” ์ž‘์€ ๊ฐœ์ฒด์˜ ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜๊ณ  ํ•ด์ฒดํ•ด์•ผ ํ•˜๋Š” ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ๋กœ ๊ฐ€๋“ ์ฐจ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ๋Š” ์กด์žฌํ•  ํ•„์š”๊ฐ€ ์—†์ง€๋งŒ ์กด์žฌํ•˜๋Š” ๋ฒ„๊ทธ์— ๋Œ€ํ•œ ๋ชจ๋“  ์ข…๋ฅ˜์˜ ๊ธฐํšŒ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ํ˜„์žฌ๋กœ์„œ๋Š” ์šฐ์•„ํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด ์ž๋™ ์„ค์ •/ํ•ด์ฒด/๋™๊ธฐํ™” ๋…ผ๋ฆฌ๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

์„ค์ • ๋ฐ ๋ถ„ํ•ด ๋‹จ๊ณ„๊ฐ€ ์žˆ๊ฑฐ๋‚˜ ํ•ญ์ƒ ์—ฐ๊ฒฐํ•ด์•ผ ํ•˜๋Š” ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ๋ง ๊ทธ๋Œ€๋กœ _๋ชจ๋“ _ ์ƒํƒœ์—์„œ ์ด ๋ฌธ์ œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜ ์ž์‹ ์€ ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์€ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์„ค์ •/ํ•ด์ œ๊ฐ€ ๋„ˆ๋ฌด ์„ฑ๊ฐ€์‹œ๊ณ  ์žฅํ™ฉํ•˜๋ฉฐ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์— AnimatorController๋Š” ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๊ณณ์—์„œ TweenAnimationBuilder๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ์ฃผ์–ด์ง„ ๋ณด๊ธฐ์—์„œ ๋” ๋งŽ์€ ์ˆ˜์˜ ์ƒํƒœ ์ €์žฅ ๊ฐœ์ฒด์— ๋„๋‹ฌํ•˜๋ฏ€๋กœ ์‹ค์ œ๋กœ ์•„๋ฌด ๊ฒƒ๋„ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ณณ์— ์ค‘์ฒฉ ๋ฐ ์ž์„ธํ•œ ์ •๋ณด๋ฅผ ๊ฐ•์š”ํ•œ๋‹ค๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

@szotp ์ €๋Š” ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค... ์ฐจ๋ผ๋ฆฌ ์šฐ๋ฆฌ๊ฐ€ ์†”๋ฃจ์…˜์„ ํ‰๊ฐ€ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ ๊ธฐ๋ณธ ์•ฑ์„ ์„ค์ •ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์Šค์Šค๋กœ ํ•  ๊ฒƒ์ด์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๊ฒƒ์ด ์ •ํ™•ํžˆ ๋ฌด์—‡์ธ์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด๊ฐ€ ๊ทธ๊ฒƒ์„ ํ•˜๋Š” ๊ฒƒ์ด ์ž˜๋ชป๋œ ์‚ฌ๋žŒ์ž…๋‹ˆ๋‹ค.

@escamoteur Baseline ์•ฑ์€ ์–ด๋ ค์›€์ด ์—†๋Š” ์†”๋ฃจ์…˜์„ ์„ค๊ณ„ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

@esDotDev ์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ๊นŒ์ง€ ์ด ๋ฒ„๊ทธ์—์„œ ์ด์™€ ๊ฐ™์€ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ๋…ผ์˜ํ–ˆ์ง€๋งŒ Hooks ์ด์™ธ์˜ ์†”๋ฃจ์…˜์€ ์†”๋ฃจ์…˜์ด ํ•ด๊ฒฐํ•œ ์˜ˆ์ œ์— ํฌํ•จ๋˜์ง€ ์•Š์€ ์ผ๋ถ€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋Ÿด ๋•Œ๋งˆ๋‹ค ๊ธฐ๊ฐ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ์„ค๋ช…์€ ์ „์ฒด ๋ฒ”์œ„๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, "12๊ฐœ์˜ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ ์ปจํŠธ๋กค๋Ÿฌ" ์‚ฌ๋ก€๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ ๋ฐฐ์—ด๊ณผ Dart์˜ ๊ธฐ๋Šฅ์  ๊ธฐ๋Šฅ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. TweenAnimationBuilder๊ฐ€ ๋˜ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘˜ ์ค‘ ์–ด๋Š ๊ฒƒ๋„ Hooks๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚ด๊ฐ€ ์ œ์•ˆํ•˜๋ฉด ๋ˆ„๊ตฐ๊ฐ€ ๋‚ด๊ฐ€ ๋†“์นœ ๊ฒƒ์„ ์ง€์ ํ•˜๊ณ  "๊ทธ๊ฒƒ์€ ... ๋•Œ๋ฌธ์— ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."๋ผ๊ณ  ๋งํ•˜๊ณ  (์˜ˆ์ œ ์ปจํ…์ŠคํŠธ์—์„œ ์ƒˆ๋กœ์šด) ๋ฌธ์ œ๋ฅผ ์ œ๊ธฐํ•  ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ๋™์˜ํ•˜๋Š” ๊ธฐ๋ณธ ์•ฑ์˜ ํ•„์š”์„ฑ์€ ๋ฌธ์ œ์˜ ์ „์ฒด ํ™•์‚ฐ์„ ํฌ๊ด„ํ•ฉ๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด๊ฒƒ์„ ์•ž์œผ๋กœ ์ถ”์ง„ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋‚ด๊ฐ€ ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค(https://github.com/flutter/flutter/issues/51752#issuecomment-670249755 ๋ฐ https://github.com /flutter/flutter/issues/51752#issuecomment-670232842). ๊ทธ๊ฒƒ์€ ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์šฐ๋ฆฌ๊ฐ€ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ์˜ ๋ฒ”์œ„๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•  ์ˆ˜ ์žˆ๋Š” ์ถœ๋ฐœ์ ์„ ์ œ๊ณตํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ชจ๋“  ์š”๊ตฌ ์‚ฌํ•ญ(์˜ˆ: @rrousselGit ์˜ ์žฌ์‚ฌ์šฉ ํ•„์š”์„ฑ, @Rudiksz ์˜ ๊นจ๋—ํ•œ ๋นŒ๋“œ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํ•„์š”์„ฑ ๋“ฑ)์„ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์†”๋ฃจ์…˜์„ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์ด๋Ÿฌํ•œ ์†”๋ฃจ์…˜์„ ํ‰๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์•ฑ์˜ ์ปจํ…์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ƒ๋‹นํžˆ ์‰ฝ๊ฒŒ ๋™์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
_Streams, AnimatorController ๋“ฑ๊ณผ ๊ด€๋ จ๋œ ์„ค์ •/ํ•ด์ œ ์ž‘์—…์„ ๊ณต์œ ํ•˜๋Š” ์šฐ์•„ํ•œ ๋ฐฉ๋ฒ•์€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ถˆํ•„์š”ํ•œ ์žฅํ™ฉํ•จ, ๋ฒ„๊ทธ ๋ฐœ์ƒ ๋ฐ ๊ฐ€๋…์„ฑ ๊ฐ์†Œ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค._

๊ทธ๊ฒƒ์— ๋™์˜ํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๊ฑฐ๊ธฐ์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•„ ์•ž์œผ๋กœ ๋‚˜์•„๊ฐ€๋ฉด ์•ˆ ๋ ๊นŒ์š”? ์šฐ๋ฆฌ๋Š” ๋จผ์ € ์ด๊ฒƒ์ด ํ•ต์‹ฌ ๋ฌธ์ œ๋ผ๋Š” ๋ฐ ๋™์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„์ง๊นŒ์ง€๋Š” ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ธ€์„ ์“ฐ๋ฉด์„œ ๋ฌธ์ œ์˜ ์ด๋ฆ„์ด ์ •ํ™•ํžˆ ์ผ์น˜ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค.
" ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๊ฑฐ๋‚˜ ๋„ˆ๋ฌด ์–ด๋ ต์Šต๋‹ˆ๋‹ค "

๋‚˜์—๊ฒŒ ๊ทธ๊ฒƒ์€ ๋งค์šฐ ๋ช…๋ฐฑํ•œ ๋ฌธ์ œ์ด๋ฉฐ, ์šฐ๋ฆฌ๋Š” ์‹ ์†ํ•˜๊ฒŒ ํ† ๋ก  ๋‹จ๊ณ„๋ฅผ ์ง€๋‚˜์„œ ๋ฌด์—‡์ด ํšจ๊ณผ๊ฐ€ ์žˆ์„์ง€ ๋ธŒ๋ ˆ์ธ์Šคํ† ๋ฐ์— ๋“ค์–ด๊ฐ€์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฏธ์„ธ ์ƒํƒœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค... ๋ญ”๊ฐ€ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ์„ ๊ฑฐ๋ผ ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋ฃจ๊ฐ€ ๋๋‚  ๋•Œ ๋งŽ์€ Flutter ๋ณด๊ธฐ๋ฅผ ์ •๋ฆฌํ•˜๊ณ  ๋” ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@Hixie ์ œ๋ฐœ ํ•˜์ง€๋งˆ. ์‚ฌ๋žŒ๋“ค์€ ์ด ๋ฌธ์ œ์— ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์•ฝ ๋ ˆ๋”ง์— ๋‹น์‹ ๊ณผ ํ•จ๊ป˜ ์ด์•ผ๊ธฐ ํ•œ ๊ฐ™์€ ์ผ์„ ํ•˜์ง€๋งŒ, SwiftUI์˜ ๋งฅ๋ฝ์—์„œ : https://github.com/szotp/SwiftUI_vs_Flutter

๋‹น์‹ ์˜ SwiftUI ์˜ˆ์ œ๋Š” ๋‹จ์ˆœํžˆ StatefulWidget ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•จ์œผ๋กœ์จ ๋ช‡ ์ค„์˜ ์ฝ”๋“œ๋กœ ๋‹คํŠธ์—์„œ ๋ณต์ œ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•Œ๋ฆฌ๋ฏธ๋ฅผ ๊ตฌ๋…ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์™ธ๋ถ€ ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š” StatefulWidgets๊ฐ€ ์žˆ์œผ๋ฉฐ ์‹ค์ œ๋กœ ๋Œ€๋ถ€๋ถ„์ด ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์•ฝ 100๊ฐœ์˜ ์‚ฌ์šฉ์ž ์ •์˜ ์œ„์ ฏ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ(๋ชจ๋‘ Stateful์€ ์•„๋‹ˆ์ง€๋งŒ) ๊ทธ ์ค‘ 15๊ฐœ๋Š” ์—ฌ๊ธฐ ์˜ˆ์ œ์—์„œ ์„ค๋ช…ํ•˜๋Š” ๋ชจ๋“  ์ข…๋ฅ˜์˜ "๊ณตํ†ต ์ƒํƒœ ๋…ผ๋ฆฌ"๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์žฅ๊ธฐ์ ์œผ๋กœ ๋ช‡ ์ค„์˜ ์ฝ”๋“œ(์ผ๋ช… ์ƒ์šฉ๊ตฌ)๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ถˆํ•„์š”ํ•œ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•œ ์ž‘์€ ์ ˆ์ถฉ์•ˆ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ, initState/didUpdate ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ์ด ๋ฌธ์ œ๋Š” ๋„ˆ๋ฌด ๊ณผ์žฅ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ์„ค๋ช…๋œ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์œ„์ ฏ์„ ๋งŒ๋“ค ๋•Œ ์ฒ˜์Œ์—๋Š” ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ "๊ตฌํ˜„"ํ•˜๋Š” ๋ฐ 5-10๋ถ„์„ ๋ณด๋‚ธ ๋‹ค์Œ ํ•ด๋‹น ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์œผ๋ฉด์„œ ์‹ค์ œ๋กœ ์œ„์ ฏ ์ž์ฒด๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์—ฐ๋งˆํ•˜๋Š” ๋ฐ ๋ฉฐ์น ์„ ํ• ์• ํ•ฉ๋‹ˆ๋‹ค. ์†Œ์œ„ ์ƒ์šฉ๊ตฌ ์„ค์ •/ํ•ด์ฒด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ์†Œ๋น„ํ•˜๋Š” ์‹œ๊ฐ„์€ ๋‚ด ์•ฑ ์ฝ”๋“œ์— ๋น„ํ•ด ์ ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งํ–ˆ๋“ฏ์ด StatefulWidget์€ ์šฉ๋„์— ๋Œ€ํ•ด ๊ฑฐ์˜ ๊ฐ€์ •ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ•๋ ฅํ•˜๊ณ  ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

์ด ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด StatefulWidget์„ ์„œ๋ธŒํด๋ž˜์‹ฑํ•˜๋Š”(๋˜๋Š” ๊ทธ๋ ‡์ง€ ์•Š์€) Flutter์— ์ƒˆ๋กœ์šด ์œ ํ˜•์˜ ์œ„์ ฏ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ์ง€๋งŒ StatefulWidget ์ž์ฒด์— ์ ์šฉํ•˜์ง€๋Š” ๋ง™์‹œ๋‹ค. ๋‚˜๋Š” "ํ›„ํฌ" ์‹œ์Šคํ…œ์ด๋‚˜ ๋งˆ์ดํฌ๋กœ์Šคํ…Œ์ดํŠธ์™€ ํ•จ๊ป˜ ์˜ค๋Š” ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ์œ„์ ฏ์„ ๋งŽ์ด ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@esDotDev ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์ด ์ง๋ฉดํ•œ ๋ฌธ์ œ๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด ๋ฌธ์ œ์˜ ์•ž๋ถ€๋ถ„์—์„œ ๋ช‡ ๊ฐ€์ง€ ์†”๋ฃจ์…˜์„ ์ œ์•ˆํ•˜๊ธฐ๋„ ํ–ˆ์Šต๋‹ˆ๋‹ค(GitHub์ด ๋ชจ๋“  ์ฃผ์„์„ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์–‘ํ•œ ๋ฒ„์ „์˜ Property ํด๋ž˜์Šค ๊ฒ€์ƒ‰, ์ง€๊ธˆ์€ ๋ฌปํž ์ˆ˜ ์žˆ์Œ). ์–ด๋ ค์›€์€ ์ด๋Ÿฌํ•œ ์ œ์•ˆ์ด ํŠน์ • ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๊ฐ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(์˜ˆ: ํ•œ ๊ฒฝ์šฐ์—๋Š” ํ•ซ ๋ฆฌ๋กœ๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•˜๊ณ  ๋‹ค๋ฅธ ๊ฒฝ์šฐ์—๋Š” didUpdateWidget์„ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค). ๊ทธ๋ž˜์„œ ๋” ๋งŽ์€ ์ œ์•ˆ์„ ํ–ˆ์ง€๋งŒ ๋‹ค๋ฅธ ๊ฒƒ์„ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์‹œ ๊ธฐ๊ฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค(๋ฌด์—‡์„ ์žŠ์–ด๋ฒ„๋ ธ๋Š”์ง€). ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ๊ทธ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋„๋ก _์ „์ฒด_ ๋ฌธ์ œ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐ ๋™์˜ํ•˜๋Š” ์ผ์ข…์˜ ๊ธฐ์ค€์„ ์„ ๊ฐ–๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.

๋ชฉํ‘œ๋Š” ๊ฒฐ์ฝ” ๋ณ€ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ œ์•ˆ๋œ ์†”๋ฃจ์…˜์ด ์œ ์—ฐ์„ฑ์ด ๋ถ€์กฑํ•˜๋‹ค๋Š” ๋น„ํŒ์ด ์ œ๊ธฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋“ค ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ๊ตฌํ˜„๋œ ์Šค๋‹ˆํŽซ ์™ธ๋ถ€์—์„œ ๊ณ„์† ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์ด ํ˜ธ์˜ ์ œ๋ชฉ์— "์–ด๋ ค์›€"์ด ์–ธ๊ธ‰๋œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ์‹์— ์œ ์—ฐ์„ฑ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.


๊ทธ๊ฒƒ์„ ๋ณด๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ƒํƒœ ๋กœ์ง์„ ์œ„ํ•ด ์œ„์ ฏ ๋ ˆ์ด์–ด๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค.
์ œ์•ˆ๋œ ์†”๋ฃจ์…˜์€ "ํ•˜์ง€๋งŒ RenderObject๋กœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค"์ž…๋‹ˆ๋‹ค.

_์žฅ๊ธฐ์ ์œผ๋กœ, ๋ช‡ ์ค„์˜ ์ฝ”๋“œ(์ผ๋ช… ์ƒ์šฉ๊ตฌ)๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ถˆํ•„์š”ํ•œ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•œ ์ž‘์€ ์ ˆ์ถฉ์•ˆ์ž…๋‹ˆ๋‹ค._

์ด ์ง„์ˆ ๊ณผ ํ•จ๊ป˜ ๋ช‡ ๊ฐ€์ง€ ๋‹ˆํŠธ :

  1. ์‹ค์ œ๋กœ ๋ช‡ ์ค„์€ ์•„๋‹™๋‹ˆ๋‹ค. ๋Œ€๊ด„ํ˜ธ, ์ค„ ๊ฐ„๊ฒฉ @overides ๋“ฑ์„ acct์— ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ„๋‹จํ•œ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ ์ปจํŠธ๋กค๋Ÿฌ์— ๋Œ€ํ•ด 10-15๊ฐœ ์ด์ƒ์˜ ์ค„์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‚ด ๋งˆ์Œ์— ์‚ฌ์†Œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค ... ์‚ฌ์†Œํ•˜์ง€ ์•Š์€ ๋ฐฉ๋ฒ•์ฒ˜๋Ÿผ. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” 3์ค„์€ ์ €์—๊ฒŒ ๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(Unity์—์„œ๋Š” Thing.DOTween() ). 15๋Š” ์›ƒ๊ธฐ๋„ค์š”.
  1. ๊ทธ๊ฒƒ์€ ๊ณ ํ†ต์ด์ง€๋งŒ ํƒ€์ดํ•‘์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. 30์ค„์ด ๊ธฐ๊ณ„์‹ ์ƒ์šฉ๊ตฌ์ธ 50์ค„ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์–ด๋ฆฌ์„์€ ์ผ์ž…๋‹ˆ๋‹ค. ๋‚œ๋…ํ™”. ์ƒ์šฉ๊ตฌ๋ฅผ ์ž‘์„ฑ _ํ•˜์ง€ ์•Š๋Š”_ ๊ฒฝ์šฐ ๊ฒฝ๊ณ  ๋˜๋Š” ๊ธฐํƒ€ ์‚ฌํ•ญ์ด ์—†๊ณ  ๋ฐฉ๊ธˆ ๋ฒ„๊ทธ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค๋Š” ์‚ฌ์‹ค์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  2. Hooks์™€ ๊ฐ™์€ ๊ฒƒ์œผ๋กœ ๋…ผ์˜ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ์˜ค๋ฒ„ํ—ค๋“œ๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๊ฐ๊ฐ์— ์†Œ์ˆ˜์˜ fxns๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด ๋ฐฐ์—ด์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Dart์—์„œ๋Š” ๋งค์šฐ ๋น ๋ฆ…๋‹ˆ๋‹ค. ํ™์–ด ์ด๋ชจ์ž…๋‹ˆ๋‹ค.

@esDotDev

๋‚˜์—๊ฒŒ ๊ทธ๊ฒƒ์€ ๋งค์šฐ ๋ช…๋ฐฑํ•œ ๋ฌธ์ œ์ด๋ฉฐ, ์šฐ๋ฆฌ๋Š” ์‹ ์†ํ•˜๊ฒŒ ํ† ๋ก  ๋‹จ๊ณ„๋ฅผ ์ง€๋‚˜์„œ ๋ฌด์—‡์ด ํšจ๊ณผ๊ฐ€ ์žˆ์„์ง€ ๋ธŒ๋ ˆ์ธ์Šคํ† ๋ฐ์— ๋“ค์–ด๊ฐ€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์œ„์ ฏ ํ™•์žฅ. ValueNotifier๊ฐ€ ๊ณตํ†ต ์‚ฌ์šฉ ํŒจํ„ด์„ ๋‹จ์ˆœํ™”ํ•˜๊ธฐ ์œ„ํ•ด ChangeNotifier๋ฅผ ํ™•์žฅํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ชจ๋“  ์‚ฌ๋žŒ์€ ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ์ž์‹ ๋งŒ์˜ StatelessWidget์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ, ๊ทธ๊ฒƒ์ด ํšจ๊ณผ์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•˜์ง€๋งŒ ๋ฐ”๋ผ๋Š” ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์• ๋‹ˆ๋ฉ”์ดํ„ฐ๊ฐ€ 1๊ฐœ๋ผ๋ฉด TweenAnimationBuilder๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฟจ, ์—ฌ์ „ํžˆ 5์ค„์˜ ์ฝ”๋“œ์™€ ๋น„์Šทํ•˜์ง€๋งŒ ๋ฌด์—‡์ด๋“  ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค ... ๋„ˆ๋ฌด ๋‚˜์˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ 2~3๊ฐœ ์žˆ์œผ๋ฉด? ์ด์ œ ์ €๋Š” ์ค‘์ฒฉ ์ง€์˜ฅ์— ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ์ด์œ ๋กœ cpl ๋‹ค๋ฅธ ์ƒํƒœ ์ €์žฅ ๊ฐœ์ฒด๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ชจ๋“  ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์—‰๋ง์ด ๋˜๊ฑฐ๋‚˜ ์ž„์˜์˜ ์„ค์ •, ์—…๋ฐ์ดํŠธ ๋ฐ ๋ถ„ํ•ด ์ปฌ๋ ‰์…˜์„ ์บก์Šํ™”ํ•˜๋Š” ๋งค์šฐ ๊ตฌ์ฒด์ ์ธ ์œ„์ ฏ์„ ๋งŒ๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋…ผ๋ฆฌ.

์œ„์ ฏ ํ™•์žฅ. ValueNotifier๊ฐ€ ๊ณตํ†ต ์‚ฌ์šฉ ํŒจํ„ด์„ ๋‹จ์ˆœํ™”ํ•˜๊ธฐ ์œ„ํ•ด ChangeNotifier๋ฅผ ํ™•์žฅํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ชจ๋“  ์‚ฌ๋žŒ์€ ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ์ž์‹ ๋งŒ์˜ StatelessWidget์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋งŒ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฑด ์Šค์ผ€์ผ์ด ์•„๋‹ˆ๋‹ค

๋ฏน์Šค์ธ์€ ๋‹ค์Œ ๋…ผ๋ฆฌ์  ์‹œ๋„์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ OP๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ํ™•์žฅ๋˜์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค.

@esDotDev

๋˜๋Š” ์„ค์ •, ์—…๋ฐ์ดํŠธ ๋ฐ ํ•ด์ œ ๋…ผ๋ฆฌ์˜ ์ž„์˜ ์ปฌ๋ ‰์…˜์„ ์บก์Šํ™”ํ•˜๋Š” ๋งค์šฐ ๊ตฌ์ฒด์ ์ธ ์œ„์ ฏ์„ ๋งŒ๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

3-4๊ฐ€์ง€ ์ข…๋ฅ˜์˜ AnimationController๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ์ผ์ข…์˜ ์œ„์ ฏ์€ ๋งค์šฐ ๊ตฌ์ฒด์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€์ฒ˜๋Ÿผ ๋“ค๋ฆฌ๋ฉฐ ์„ค์ •/ํ•ด์ œ ๋กœ์ง์˜ ์ž„์˜ ์ˆ˜์ง‘์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ํ™•์‹คํžˆ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€๊ฐ€ ๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์ด๊ฒƒ์ด initState/didUpdateWidget ๋ฉ”์†Œ๋“œ๊ฐ€ ์ฒ˜์Œ์— ๋…ธ์ถœ๋˜๋Š” ์ด์œ ์ด๋ฏ€๋กœ ์›ํ•˜๋Š” ๋Œ€๋กœ ์„ค์ •์„ ๋ฌด์ž‘์œ„๋กœ ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๊ธด initState ๋ฉ”์„œ๋“œ๋Š” 5์ค„์˜ ์ฝ”๋“œ์ด๋ฉฐ, ์œ„์ ฏ์€ ๊ณผ๋„ํ•œ ์ค‘์ฒฉ์„ ๊ฒช์ง€ ์•Š์œผ๋ฏ€๋กœ ์š”๊ตฌ ์‚ฌํ•ญ๊ณผ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ํ™•์‹คํžˆ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋˜๋Š” ๋‹ค๋ฅธ ๊ฐœ๋ฐœ ์Šคํƒ€์ผ.

@esDotDev

3. Hooks์™€ ๊ฐ™์€ ๊ฒƒ์œผ๋กœ ๋…ผ์˜ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๊ฐ๊ฐ์— ์†Œ์ˆ˜์˜ fxns๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด ๋ฐฐ์—ด์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Dart์—์„œ๋Š” ๋งค์šฐ ๋น ๋ฆ…๋‹ˆ๋‹ค. ํ™์–ด ์ด๋ชจ์ž…๋‹ˆ๋‹ค.

์ œ์•ˆ๋œ ์†”๋ฃจ์…˜์ด ์™„์ „ํžˆ ์‚ฌ์‹ค์ด ์•„๋‹Œ flutter_hooks ํŒจํ‚ค์ง€์™€ ๊ฐ™์€ ๊ฒƒ์ด๋ผ๋ฉด. ์˜ˆ, ๊ฐœ๋…์ ์œผ๋กœ๋Š” ํ•จ์ˆ˜๊ฐ€ ํฌํ•จ๋œ ๋ฐฐ์—ด์ด์ง€๋งŒ ๊ตฌํ˜„์€ ์‚ฌ์†Œํ•˜๊ฑฐ๋‚˜ ํšจ์œจ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚ด ๋ง์€, ๋‚ด๊ฐ€ ํ‹€๋ฆด ์ˆ˜๋„ ์žˆ์ง€๋งŒ HookElement๊ฐ€ ์ž์ฒด ๋นŒ๋“œ ๋ฉ”์„œ๋“œ์—์„œ ์ž์ฒด์ ์œผ๋กœ ๋‹ค์‹œ ๋นŒ๋“œํ•ด์•ผ ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค!
๋˜ํ•œ ๋ชจ๋“  ๋‹จ์ผ ์œ„์ ฏ ๋นŒ๋“œ์—์„œ ํ›„ํฌ๋ฅผ ์ดˆ๊ธฐํ™”, ์žฌ์ดˆ๊ธฐํ™” ๋˜๋Š” ํ๊ธฐํ•ด์•ผ ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ์ƒ๋‹นํ•œ ์˜ค๋ฒ„ํ—ค๋“œ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ์˜ณ์ง€ ์•Š๋‹ค๊ณ  ๋Š๋ผ๋ฏ€๋กœ ๋‚ด๊ฐ€ ํ‹€๋ ธ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

@brianegan ์˜ ์•„ํ‚คํ…์ฒ˜ ์˜ˆ์ œ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋น„๊ต๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ ์•ฑ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚ด๊ฐ€ ์—ฌ๊ธฐ์— ๋ผ์–ด๋“ค ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ด๊ฒƒ์ด ์ด๋ฏธ ๋งํ–ˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ React์—์„œ ์šฐ๋ฆฌ๋Š” ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ปดํฌ๋„ŒํŠธ/์œ„์ ฏ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ์ต์ˆ™ํ•˜๋‹ค๋ฉด ๋ฌด์„ญ๊ฒŒ ๋“ค๋ฆด ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์—ฌ๊ธฐ์—์„œ ์ˆ˜๋ช… ์ฃผ๊ธฐ๊ฐ€ ์‹ค์ œ๋กœ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ props๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ƒํƒœ ๋˜๋Š” ์ž‘์—…์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ/์œ„์ ฏ์„ ๋นŒ๋“œํ•  ๋•Œ ํ•ด๋‹น ์ƒํƒœ/props๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ฌด์–ธ๊ฐ€๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: ์ด ์Šค๋ ˆ๋“œ์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ -userId ์†Œํ’ˆ์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์‚ฌ์šฉ์ž์˜ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์œ„์ ฏ์˜ ๋ชจ๋“  props๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค userId ๋ณ€๊ฒฝ์˜ "ํšจ๊ณผ"๋กœ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

์ •๋ฆฌ์— ๋Œ€ํ•ด์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ง€๋งŒ, "๋ชจ๋“  props/state๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ๋  ๋•Œ X๋ฅผ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•ด์•ผ ํ•จ์„ ๊ธฐ์–ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ „์ฒด ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํŒŒ๊ดด๋  ๋•Œ".

์ €๋Š” Flutter๋ฅผ ํ•œ๋™์•ˆ ์ž‘์„ฑํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ํ˜„์žฌ์˜ ๋ถ„์œ„๊ธฐ๋‚˜ ์ด ์ ‘๊ทผ ๋ฐฉ์‹์ด ํ˜„์žฌ Flutter ์‚ฌ๊ณ  ๋ฐฉ์‹์— ๋ฏธ์น  ์ œํ•œ ์‚ฌํ•ญ์„ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฌ๋ ค๊ณ  ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ €๋Š” ๋‹ค์–‘ํ•œ ์˜๊ฒฌ์— ์—ด๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” React hooks์— ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋‚ด๊ฐ€ ๋ผ์ดํ”„์‚ฌ์ดํด ํŒจ๋Ÿฌ๋‹ค์ž„์— ๋„ˆ๋ฌด ๊นŠ์ด ๋ฟŒ๋ฆฌ๋ฐ•ํ˜€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด๊ฐ€ ์†Œ๊ฐœ๋˜์—ˆ์„ ๋•Œ์™€ ๊ฐ™์€ ํ˜ผ๋ž€์„ ๊ฒช๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@escamoteur @Rudiksz @Hixie ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€์ด ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์‹œ์ž‘ํ•˜๋Š” ๊ณณ์œผ๋กœ ์ดˆ๋Œ€๋ฐ›์€ ๊ฒƒ์„ @TimWhiting์— ์˜ํ•ด ์ƒ์„ฑ ๋œ GitHub์˜ ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ์—ˆ๋‹ค. ๊ฐ ๊ฐœ์ธ/๊ทธ๋ฃน์€ ๋ฏธ๋ฆฌ ์ •์˜๋œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€์™€ ๊ฐ™์€ ์™„์ „ํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ ์•ฑ์€ ์•„๋‹ˆ์ง€๋งŒ ๋” ๋ณต์žกํ•œ ์˜ˆ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ๊ฒฝ์šฐ ์•ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ฌธ์ œ๋ฅผ ๋…ผ์˜ํ•˜๊ณ  ๋” ๋‚˜์€ API๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. @TimWhiting ์€ ๊ด€์‹ฌ ์žˆ๋Š” ์‚ฌ๋žŒ์„ ์ดˆ๋Œ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/TimWhiting/local_widget_state_approaches

Jetpack compose ๋Š” ์—ฌ๊ธฐ ์—์„œ react ์™€ ๋น„๊ตํ•œ hook๊ณผ๋„ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

@satvikpendem @TimWhiting ๋ฉ‹์ง€๋„ค์š” ! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

@esDotDev
๋งค์šฐ ๊ตฌ์ฒด์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ์„ค์ •/ํ•ด์ œ ๋กœ์ง์˜ ์ž„์˜ ์ˆ˜์ง‘ ์ง€์›์€ ํ™•์‹คํžˆ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€๊ฐ€ ๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๊ฐˆ๊ณ ๋ฆฌ๊ฐ€ ๋จธ๋ฆฌ๋ฅผ ๋•Œ๋ฆฌ๋Š” ๋ชป์ž…๋‹ˆ๋‹ค. ๊ฐ ์œ ํ˜•์˜ ๊ฐœ์ฒด๋Š” ์ž์ฒด ์„ค์ • ๋ฐ ๋ถ„ํ•ด๋ฅผ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์• ๋‹ˆ๋ฉ”์ดํ„ฐ๋Š” ์ŠคํŠธ๋ฆผ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์Šค์Šค๋กœ๋ฅผ ์ƒ์„ฑ, ์—…๋ฐ์ดํŠธ ๋ฐ ํŒŒ๊ดดํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Hooks๋Š” ํŠนํžˆ ๋ทฐ ์ „์ฒด์— ํฉ์–ด์ ธ ์žˆ๋Š” ์ƒํƒœ ์Šค์บํด๋”ฉ์˜ '์ž„์˜ ์ปฌ๋ ‰์…˜' ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋ณด๊ธฐ ์ฝ”๋“œ์˜ ๋Œ€๋ถ€๋ถ„์ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ฐ ๋ ˆ์ด์•„์›ƒ ํ˜•์‹ํ™”์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ ์Šน๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ํ”„๋กœ์ ํŠธ์—์„œ ๋™์ผํ•œ ์ผ๋ฐ˜์ ์ธ ์ƒ์šฉ๊ตฌ๋ฅผ ์ˆจ๊ธฐ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž ์ง€์ • ์œ„์ ฏ์„ ๋งŒ๋“ค๋„๋ก ๊ฐ•์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๊ธด initState ๋ฉ”์„œ๋“œ๋Š” 5์ค„์˜ ์ฝ”๋“œ์ด๋ฉฐ, ์œ„์ ฏ์€ ๊ณผ๋„ํ•œ ์ค‘์ฒฉ์„ ๊ฒช์ง€ ์•Š์œผ๋ฏ€๋กœ ์š”๊ตฌ ์‚ฌํ•ญ๊ณผ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ํ™•์‹คํžˆ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋˜๋Š” ๋‹ค๋ฅธ ๊ฐœ๋ฐœ ์Šคํƒ€์ผ.

๋‚ด ๊ฒƒ๋„. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ initState() + dispose() + didUpdateDependancies()์ด๋ฉฐ ๋งˆ์ง€๋ง‰ 2๊ฐœ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ˆ„๋ฝ๋˜๋ฉด ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ‘œ์ค€ ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. 1๊ฐœ์˜ ์ŠคํŠธ๋ฆผ ์ปจํŠธ๋กค๋Ÿฌ์™€ 2๊ฐœ์˜ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ณด๊ธฐ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋ณผ ์ˆ˜์žˆ๋Š” ํ•œ 3 ๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. 30์ค„ ์ •๋„์˜ ์ƒ์šฉ๊ตฌ๋ฅผ ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•˜๊ณ  ์ผ๋ถ€ ๋ฏน์Šค์ธ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์žฅํ™ฉํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ฒ˜์Œ์—๋Š” ๋”ฐ๋ผ๊ฐ€๊ธฐ๊ฐ€ ์ƒ๋‹นํžˆ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
  2. ๋ณด๊ธฐ ์ฝ”๋“œ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ์•ฝ 15๊ฐœ์˜ ๋“ค์—ฌ์“ฐ๊ธฐ ์ˆ˜์ค€์— ๋Œ€ํ•ด 2๊ฐœ์˜ TweenAnimationBuilder์™€ StreamBuilder๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ์ „ํžˆ ์ŠคํŠธ๋ฆผ์— ๋Œ€ํ•œ ๋งŽ์€ ์ƒ์šฉ๊ตฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. 3๊ฐœ์˜ ์ƒํƒœ ์ €์žฅ ํ•˜์œ„ ๊ฐœ์ฒด๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์‚ฌ์šฉ์ž ์ •์˜ ์ดˆ๊ธฐํ™”/ํŒŒ๊ธฐ ์ฝ”๋“œ๋ฅผ ์ •์˜ํ•˜๋ ค๋ฉด 6์ค„์˜ ๋“ค์—ฌ์“ฐ๊ธฐ๋˜์ง€ ์•Š์€ ์ฝ”๋“œ๋ฅผ build() ๋งจ ์œ„์— ์ถ”๊ฐ€ํ•˜์„ธ์š”.

SingleStreamBuilderDoubleAnimationWidget์ธ ๋„ค ๋ฒˆ์งธ ์˜ต์…˜์ด ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๊ฒƒ์€ ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ ์ž„์‹œ ์ž‘์—…์ด๋ฉฐ ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฝค ์„ฑ๊ฐ€์‹ญ๋‹ˆ๋‹ค.

๋˜ํ•œ ์ƒˆ๋กœ์šด ๊ฐœ๋ฐœ์ž์˜ ์ธ์ง€ ๋ถ€ํ•˜ 3์€ ๋‹ค๋ฅธ 2๋ณด๋‹ค ํ›จ์”ฌ ๋‚ฎ์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์ƒˆ๋กœ์šด ๊ฐœ๋ฐœ์ž๋Š” TweenAnimationBuilder์˜ ์กด์žฌ์กฐ์ฐจ ๋ชจ๋ฅด๊ณ , ๋‹จ์ˆœํžˆ SingleTickerProvider์˜ ๊ฐœ๋…์„ ๋ฐฐ์šฐ๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ์ž‘์—…์ž…๋‹ˆ๋‹ค. "์• ๋‹ˆ๋ฉ”์ดํ„ฐ๋ฅผ ์ฃผ์„ธ์š”"๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๊ณ  ๊ฐ•๋ ฅํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์˜ค๋Š˜ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ฝ”๋”ฉํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•  ๊ฒƒ์ด๋‹ค.

2. 2๊ฐœ์˜ TweenAnimationBuilder์™€ StreamBuilder๋ฅผ ์•ฝ 15๊ฐœ์˜ ๋“ค์—ฌ์“ฐ๊ธฐ ์ˆ˜์ค€์— ๋Œ€ํ•ด ์‚ฌ์šฉํ•˜์—ฌ ๋ณด๊ธฐ ์ฝ”๋“œ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์—๋„ ์ŠคํŠธ๋ฆผ์— ๋Œ€ํ•œ ์ƒ์šฉ๊ตฌ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋ฅธ์ชฝ. 15๋‹จ๊ณ„ ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‹ค์ œ ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ์„ธ์š”.

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ 30์ค„์˜ ์ฝ”๋“œ๋ฅผ 6์ค„ + ์ˆ˜๋ฐฑ ์ค„๋กœ ๋Œ€์ฒดํ•˜๋ฉด ์ธ์ง€ ๋ถ€ํ•˜๊ฐ€ โ€‹โ€‹์–ด๋–ป๊ฒŒ ๊ฐ์†Œํ•ฉ๋‹ˆ๊นŒ? ๋„ค, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•˜๋Š” "๋งˆ๋ฒ•"์€ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทœ์น™์€ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํ›„ํฌ ํŒจํ‚ค์ง€๋Š” ํ›„ํฌ๊ฐ€ ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ์—์„œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋ถˆํ™•์‹คํ•œ ์šฉ์–ด๋กœ ์•Œ๋ ค์ค๋‹ˆ๋‹ค. ์ด์ œ ๊ฑฑ์ •ํ•ด์•ผ ํ•  ์ถ”๊ฐ€ ์ œ์•ฝ ์กฐ๊ฑด์ด ์žˆ์Šต๋‹ˆ๋‹ค.

15,000์ค„์˜ ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ focusnodes, textcontrollers, singletickerproviders ๋˜๋Š” ๋‚ด statefulwidgets์˜ ๋‹ค์–‘ํ•œ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ 200์ค„ ๋ฏธ๋งŒ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์–ด๋–ค ์ธ์ง€ ๊ณผ๋ถ€ํ•˜์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@Rudiksz ์ˆ˜๋™ ๊ณต๊ฒฉ์„ ์ค‘์ง€ํ•˜์‹ญ์‹œ์˜ค.
์šฐ๋ฆฌ๋Š” ์‹ธ์šฐ์ง€ ์•Š๊ณ  ๋™์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


ํ›„ํฌ ์ œ์•ฝ ์กฐ๊ฑด์€ ๊ฐ€์žฅ ์ ์€ ๊ฑฑ์ •๊ฑฐ๋ฆฌ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ํ›„ํฌ์— ๋Œ€ํ•ด ๊ตฌ์ฒด์ ์œผ๋กœ ๋งํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•„์š”ํ•˜๋‹ค๋ฉด ๋‹ค๋ฅธ ํ•ด๊ฒฐ์ฑ…์„ ์ œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•œ ๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ์œ„์ ฏ์€ ๋นŒ๋“œ ๋‚ด์—์„œ๋งŒ ๋ฌด์กฐ๊ฑด์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ํ›„ํฌ ์ œ์•ฝ ์กฐ๊ฑด๊ณผ ๋™์ผํ•˜์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์ด ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๋ถˆํ‰ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์œ„์ ฏ์€ ๋นŒ๋“œ ๋‚ด์—์„œ๋งŒ ๋ฌด์กฐ๊ฑด์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ํ›„ํฌ ์ œ์•ฝ ์กฐ๊ฑด๊ณผ ๋™์ผํ•˜์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์ด ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๋ถˆํ‰ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์•„๋‹ˆ์˜ค, ๋™์ผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ์ œ์‹œ๋œ ๋ฌธ์ œ๋Š” _prepares_ ์œ„์ ฏ์ด _before_ (์žฌ)๋นŒ๋“œ๋˜๋Š” ์ฝ”๋“œ์™€ ๊ด€๋ จ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ƒํƒœ, ์ข…์†์„ฑ, ์ŠคํŠธ๋ฆผ, ์ปจํŠธ๋กค๋Ÿฌ ๋“ฑ์„ ์ค€๋น„ํ•˜๊ณ  ํŠธ๋ฆฌ ๊ตฌ์กฐ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ผ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋’ค์— ์ˆจ๊ฒจ์ ธ ์žˆ๋”๋ผ๋„ ์ด๋“ค ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ๋นŒ๋“œ ๋ฉ”์„œ๋“œ์— ์žˆ์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.
ํ•ด๋‹น ๋…ผ๋ฆฌ์˜ ์ง„์ž…์ ์€ ๋นŒ๋“œ ๋ฉ”์„œ๋“œ์— ์žˆ์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์–ด๋–ค ์ข…๋ฅ˜์˜ ์ดˆ๊ธฐํ™” ๋…ผ๋ฆฌ๋ฅผ ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ์— ๋„ฃ๋„๋ก ๊ฐ•์š”ํ•˜๋Š” ๊ฒƒ์€ ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ์—์„œ ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๋„๋ก "๊ฐ•์ œ"ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œ ๋ฐฉ๋ฒ•์˜ ์ „์ฒด ์ด์œ ๋Š” ๊ธฐ์กด ์ƒํƒœ(๋ณ€์ˆ˜ ์ง‘ํ•ฉ)๋ฅผ ๊ฐ€์ ธ์™€์„œ ๊ทธ๋ ค์ง€๋Š” ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐ˜๋Œ€๋กœ, ๋‚˜๋Š” initState/didUpdateWidget ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์— ์œ„์ ฏ์„ ๋นŒ๋“œํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋„๋ก ๊ฐ•์š”ํ•˜๋Š” ๊ฒƒ๋„ ๋ฐ˜๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ์™€ โ€‹โ€‹๊ฐ™์ด statefulwidget ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋Š” ๋งค์šฐ ๋ช…ํ™•ํ•œ ์—ญํ• ์„ ํ•˜๋ฉฐ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ด€์‹ฌ์‚ฌ๋กœ ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋งค์šฐ ์‰ฝ๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๊ฐœ๋…์ ์œผ๋กœ ์—ฌ๊ธฐ์—์„œ ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ์‹ค์ œ ๋ฌธ์ œ๋กœ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ์นด์šดํ„ฐ ์•ฑ์ด ์•„๋‹Œ ์‹ค์ œ ์˜ˆ๊ฐ€ ๋งˆ์Œ์„ ๋ฐ”๊พธ๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ์ œ๊ฐ€ ์ตœ๊ทผ์— ์‹คํ—˜ํ•œ Riverpod ์—๋Š” ์ œ์•ฝ์ด ์—†๋Š” ๋งค์šฐ ๊ฐˆ๊ณ ๋ฆฌ ๊ฐ™์€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

Consumer(
  provider: provider,
  builder: (context, value) {
    return Consumer(
      provider: provider2,
      builder: (context, value2) {
        return Text('$value $value2');
      },
    );
  },
)

๋‹ค์Œ์„ ํ•จ์œผ๋กœ์จ:

Consumer(
  builder (context, watch) {
    final value = watch(provider);
    final value2 = watch(provider2);
  },
)

watch ๋ฅผ ์กฐ๊ฑด๋ถ€๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ๊ณณ:

Consumer(
  builder: (context, watch) {
    final value = watch(provider);
    if (something) {
      final value2 = watch(provider2);
    }
  },
)

์‚ฌ์šฉ์ž ์ •์˜ StatelessWidget / StatefulWidget ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Consumer ์™„์ „ํžˆ ์ œ๊ฑฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

class Example extends ConsumerStatelessWidget {
  <strong i="21">@override</strong>
  Widget build(ConsumerBuildContext context) {
    final value = context.watch(provider);
    final value2 = context.watch(provider2);
  }
}

์ฃผ์š” ๋ฌธ์ œ๋Š” ์ด๊ฒƒ์ด ํ•œ ์ข…๋ฅ˜์˜ ๊ฐœ์ฒด์—๋งŒ ํ•ด๋‹น๋˜๋ฉฐ ๊ฐœ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ์žฌ๊ตฌ์ถ• ๊ฐ„์— ์ผ๊ด€๋œ hashCode๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์— ์˜์กดํ•˜์—ฌ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ hooks์˜ ์œ ์—ฐ์„ฑ๊ณผ๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ€๋‹ค.

@rrousselGit ๋‚ด๊ฐ€ ํ™•์žฅํ•˜์ง€ ์•Š๊ณ  ์ƒ๊ฐ StatelessWidget / StatefulWidget ์ˆ˜์—…์„ํ•˜๊ณ  ConsumerStatelessWidget ๊ฐ™์€ ๊ฒƒ์„ ๋งŒ๋“ค์–ด, ๊ฐ™์€ ๊ฒƒ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค context.watch ์— ํ™•์žฅ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ BuildContext ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ๊ณต๊ธ‰์ž๊ฐ€ InheritedWidgets์™€ ํ•จ๊ป˜ watch ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฑด ๋‹ค๋ฅธ ์ฃผ์ œ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์œผ๋กœ InheritedWidgets์— ์˜์กดํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. https://github.com/flutter/flutter/issues/30062

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด InheritedWidgets๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด https://github.com/flutter/flutter/issues/12992 ๋ฐ https://github.com/flutter/flutter/pull/33213 ๋•Œ๋ฌธ์— ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

๊ฐœ๋…์ ์œผ๋กœ ์—ฌ๊ธฐ์—์„œ ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ์‹ค์ œ ๋ฌธ์ œ๋กœ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

Flutter๋ฅผ SwiftUI์™€ ๋น„๊ตํ•˜๋ฉด ์‹ค์ œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ด ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

Flutter์™€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์—ด์‹ฌํžˆ ์ผํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณด๊ธฐ๊ฐ€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. AnimatedBuilder, StreamBuilder, Consumer, AnimatedOpacity ๋“ฑ ๊ฐ ํŠน์ • ์‚ฌ๋ก€์— ๋Œ€ํ•œ ๋ž˜ํผ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. StatefulWidget์€ ์ด๋Ÿฌํ•œ ์ž‘์€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•˜์ง€๋งŒ ๋„ˆ๋ฌด ๋‚ฎ์€ ์ˆ˜์ค€์ž…๋‹ˆ๋‹ค. ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋„๋ฉ”์ธ ํŠน์ • ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ฒฝ์šฐ ๋‹ค์ˆ˜์˜ ํ…์ŠคํŠธ ์ปจํŠธ๋กค๋Ÿฌ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์š”๊ตฌํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ํ•ด๊ฒฐ์ฑ…์€ ์ด์•Œ์„ ๊นจ๋ฌผ๊ณ  ๋ชจ๋“  ์ƒ์šฉ๊ตฌ๋ฅผ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์‹ ์ค‘ํ•˜๊ฒŒ ๊ตฌ์„ฑ๋œ ๊ณต๊ธ‰์ž ๋ฐ ์ฒญ์ทจ์ž ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์–ด๋–ค ์ ‘๊ทผ ๋ฐฉ์‹๋„ ๋งŒ์กฑ์Šค๋Ÿฝ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@rrousselGit์ด ๋งํ•˜๋Š” ๊ฒƒ๊ณผ
์ƒํƒœ ์œ ์ง€์˜ ๊ฒฝ์šฐ ๋ฌธ์ œ๋Š” ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ž๋™ํ™”๋  ์ˆ˜ ์žˆ๋Š” ์ง€๋ฃจํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด ์ž‘์—…์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฑด ๊ทธ๋ ‡๊ณ , ํ›„ํฌ๊ฐ€ ์ด๊ฒƒ์„ ์ „ํ˜€ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ›„ํฌ๋Š” flutter์˜ ๋‚ด๋ถ€๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๊ฐ€๋Šฅํ•œ ์œ ์ผํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

StatefulWidget์€ ์ด๋Ÿฌํ•œ ์ž‘์€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•˜์ง€๋งŒ, ๋‹ค์ˆ˜์˜ ํ…์ŠคํŠธ ์ปจํŠธ๋กค๋Ÿฌ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์š”๊ตฌํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋Š” ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ ๋„๋ฉ”์ธ ํŠน์ • ๊ตฌ์„ฑ ์š”์†Œ์—๋Š” ๋„ˆ๋ฌด ๋‚ฎ์€ ์ˆ˜์ค€์ž…๋‹ˆ๋‹ค.

์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋„๋ฉ”์ธ ํŠน์ • ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋นŒ๋“œํ•˜๋ ค๋ฉด ๋†’์€ ์ˆ˜์ค€์˜ ์œ„์ ฏ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ๋งํ•  ๋•Œ ํ˜ผ๋ž€์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค. ๋ณดํ†ต์€ ์ •๋ฐ˜๋Œ€์ž…๋‹ˆ๋‹ค.

AnimatedBuilder, StreamBuilder, Consumer, AnimatedOpacity๋Š” ๋ชจ๋‘ ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์œ„์ ฏ์ž…๋‹ˆ๋‹ค. ํŠน์ • ๋…ผ๋ฆฌ๊ฐ€ ์žˆ์–ด์„œ ์ด๋Ÿฌํ•œ ์ƒ์œ„ ์ˆ˜์ค€ ์œ„์ ฏ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์œ„์ ฏ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ํ•˜์œ„ ์ˆ˜์ค€ API๋กœ ๋“œ๋กญ๋‹ค์šดํ•˜์—ฌ ๋‚˜๋งŒ์˜ ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์†Œ์œ„ ์ƒ์šฉ๊ตฌ๋ผ๊ณ  ํ•˜๋Š” ๊ฒƒ์€ ๋‚ด ๊ณ ์œ ํ•œ ์œ„์ ฏ์ด ์ŠคํŠธ๋ฆผ, ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ, ์ปจํŠธ๋กค๋Ÿฌ ๋“ฑ์˜ ๊ณ ์œ ํ•œ ์กฐํ•ฉ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ›„ํฌ, ํ›„ํฌ์™€ ๊ฐ™์€ ๋™์ž‘ ๋˜๋Š” ์‹ฌ์ง€์–ด "์ž๋™ํ™”"๋ฅผ ์˜นํ˜ธํ•˜๋Š” ๊ฒƒ์€ ์†Œ์œ„ ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ๋ˆ„๊ตฌ๋‚˜ ๊ฐ–๊ณ  ์‹ถ์–ดํ•˜๋Š” ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋†’์€ ์ˆ˜์ค€์˜ ๋…ผ๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ฎ์€ ์ˆ˜์ค€์˜ ์œ„์ ฏ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ƒํƒœ ์œ ์ง€์˜ ๊ฒฝ์šฐ ๋ฌธ์ œ๋Š” ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ž๋™ํ™”๋  ์ˆ˜ ์žˆ๋Š” ์ง€๋ฃจํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด ์ž‘์—…์ž…๋‹ˆ๋‹ค.

๋‹ค์‹œ. ๋‹ค์ˆ˜์˜ ํ…์ŠคํŠธ ์ปจํŠธ๋กค๋Ÿฌ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ์š”๊ตฌํ•˜๋Š” ๋ชจ๋“  "__!

@rrousselGit์ด ๋งํ•˜๋Š” ๊ฒƒ๊ณผ

์ €๋Š” 6-7๋…„ ์ „์— ios์™€ android ๊ฐœ๋ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค(Android๊ฐ€ ๋จธํ‹ฐ๋ฆฌ์–ผ ๋””์ž์ธ์œผ๋กœ ์ „ํ™˜ํ–ˆ์„ ๋•Œ). ๊ทธ๋ฆฌ๊ณ  ์ด ๊ด€๋ฆฌ ๋ฐ ์žฌํ™œ์šฉ ๋ณด๊ธฐ ์ค‘ ์–ด๋–ค ๊ฒƒ๋„ ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ๋˜ ๊ธฐ์–ต์ด ์—†์œผ๋ฉฐ Flutter๊ฐ€ ๋” ์ข‹๊ฑฐ๋‚˜ ๋‚˜์˜๊ฒŒ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ํ˜„์žฌ์˜ ์ผ์— ๋Œ€ํ•ด ๋งํ•  ์ˆ˜ ์—†๋‹ค. ๋‚˜๋Š” Swift์™€ Kotlin์ด ์ถœ์‹œ๋˜์—ˆ์„ ๋•Œ ๊ทธ๋งŒ๋’€๋‹ค.

StatefulWidgets์— ๊ฐ•์ œ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ์ƒ์šฉ๊ตฌ๋Š” ์ฝ”๋“œ ๊ธฐ๋ฐ˜์˜ ์•ฝ 1%์ž…๋‹ˆ๋‹ค. ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด๊ฐ€์š”? ์ฝ”๋“œ์˜ ๋ชจ๋“  ๋ผ์ธ์€ ์ž ์žฌ์ ์ธ ๋ฒ„๊ทธ ์†Œ์Šค์ด๋ฏ€๋กœ ํ™•์‹คํ•ฉ๋‹ˆ๋‹ค. ๋ฒˆ๊ฑฐ๋กญ๋‚˜์š”? 15000์—์„œ 200์ค„์˜ ์ฝ”๋“œ๊ฐ€ ๋‚˜์˜ค๋‚˜์š”? ๋‚˜๋Š” ์ •๋ง๋กœ ๊ทธ๋ ‡๊ฒŒ ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ ์ œ ์ƒ๊ฐ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. Flutter์˜ ํ…์ŠคํŠธ/์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ์ธ focusnodes์—๋Š” ๋ชจ๋‘ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์ง€๋งŒ ์žฅํ™ฉํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ๋ฌด์—‡์„ ๊ฐœ๋ฐœํ•˜์—ฌ ๋„ˆ๋ฌด ๋งŽ์€ ์ƒ์šฉ๊ตฌ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š”์ง€ ์ •๋ง ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ ์ฃผ์„ ์ค‘ ์ผ๋ถ€๋ฅผ ๋“ค์œผ๋ฉด 1์ค„ ๋Œ€์‹  5์ค„์˜ ์ฝ”๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด 5๋ฐฐ ๋” ์–ด๋ ค์šด ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๊ฐ AnimationController์— ๋Œ€ํ•ด initState ๋ฐ dispose๋ฅผ ์„ค์ •ํ•˜๋Š” ๋Œ€์‹ ์— ํ•œ ๋ฒˆ๋งŒ ์ˆ˜ํ–‰ํ•˜๊ณ  ํ•ด๋‹น ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ์›๋ฆฌ, ์žฌ์‚ฌ์šฉ์„ฑ. ๋‚˜๋Š” ๋นŒ๋“œ ๊ธฐ๋Šฅ์— ํ›„ํฌ๋ฅผ ๋„ฃ๋Š” ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€๋งŒ ๋ถ„๋ช…ํžˆ ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋ฅผ ๋ณด๋Š” ์‚ฌ๋žŒ๊ณผ ๋ณด์ง€ ๋ชปํ•˜๋Š” ์‚ฌ๋žŒ์˜ ์ฐจ์ด์ ์€ ์ „์ž๋Š” React, Swift, Kotlin๊ณผ ๊ฐ™์ด ์ด์ „์— ํ›„ํฌ์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ํ›„์ž๋Š” ์ˆœ์ˆ˜ Java์—์„œ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ. ๋‚ด ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด ํ™•์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ํ›„ํฌ๋ฅผ ์‹œ๋„ํ•˜๊ณ  ํ‘œ์ค€ ๋ฐฉ์‹์œผ๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ข…์ข… ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์ œ ๊ฒฝํ—˜์ƒ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์••๋‹ˆ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด ์ €๋Š” ์ž‘์€ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•ด flutter_hooks๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•œ ๋‹ค์Œ ๊ธฐ๋ณธ ๋ฐฉ์‹์œผ๋กœ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ํšŒ์˜์ ์ธ ์‚ฌ๋žŒ๋“ค์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. @Hixie ์˜ ์ œ์•ˆ์ฒ˜๋Ÿผ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์•ฑ ๋ฒ„์ „์„ ๋งŒ๋“œ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋ฌผ๋ก  ๊ทธ๋ ‡๊ฒŒ ํ•  ๊ฒƒ์ด์ง€๋งŒ). ์ €๋Š” ๊ฐ ์‚ฌ๋žŒ์ด ์ฐจ์ด์ ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ง์ ‘ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค.

@Hixie ์˜ ์ œ์•ˆ์ฒ˜๋Ÿผ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์•ฑ ๋ฒ„์ „์„ ๋งŒ๋“œ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋ฌผ๋ก  ๊ทธ๋ ‡๊ฒŒ ํ•  ๊ฒƒ์ด์ง€๋งŒ). ์ €๋Š” ๊ฐ ์‚ฌ๋žŒ์ด ์ฐจ์ด์ ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ง์ ‘ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ณต๊ธ‰์ž๋ฅผ ์‹œ๋„ํ•˜๋Š” ๋ฐ ๋ฉฐ์น ์„ ๋‚ญ๋น„ํ•˜๊ณ  ๋ธ”๋ก์„ ์‹œ๋„ํ•˜๋Š” ๋ฐ ๋” ๋งŽ์€ ๋‚ ์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ์ข‹์€ ์†”๋ฃจ์…˜์ด๋ผ๋Š” ๊ฒƒ์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋‹น์‹ ์„ ์œ„ํ•ด ์ž‘๋™ํ•œ๋‹ค๋ฉด, ์ข‹์Šต๋‹ˆ๋‹ค.

๋‚˜ ์‹ฌ์ง€์–ด ๋‹น์‹ ์ด ๊ฒช๊ณ ์žˆ๋Š” ๋ฌธ์ œ์— ์ œ์•ˆ ๋œ ์†”๋ฃจ์…˜์„ ์‹œ๋„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์˜ ์ด์ ์„ ์ฆ๋ช…ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ํ”Œ๋Ÿฌํ„ฐ ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๊ณ  ๊ตฌํ˜„์„ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ์‹ซ๋‹ค.

์–ด๋–ค ์ƒ์šฉ๊ตฌ ๊ฐ์†Œ ์ฝ”๋“œ๊ฐ€ ํ”„๋ ˆ์ž„์›Œํฌ์— ์ถ”๊ฐ€๋˜๋”๋ผ๋„ Stateful/StatelessWidget์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ์œ ์ง€๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ด ๋Œ€ํ™”์— ๋” ์ด์ƒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ โ€‹โ€‹์—†์ด Dart๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€์ƒ์˜ ์„ธ๊ณ„์—์„œ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋…ผ์˜๋œ ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  return ValueListenableBuilder<String>(
    valueListenable: someValueListenable,
    builder: (context, value, _) {
      return StreamBuilder<int>(
        stream: someStream,
        builder: (context, value2) {
          return TweenAnimationBuilder<double>(
            tween: Tween(...),
            builder: (context, value3) {
              return Text('$value $value2 $value3');
            },
          );
        },
      );
    },
  );
}

์ด ์ฝ”๋“œ๋Š” ์ฝ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ตฌ๋ฌธ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•˜๋Š” ์ƒˆ ํ‚ค์›Œ๋“œ๋ฅผ ๋„์ž…ํ•˜์—ฌ ๊ฐ€๋…์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  final value = keyword ValueListenableBuilder(valueListenable: someValueListenable);
  final value2 = keyword StreamBuilder(stream: someStream);
  final value3 = keyword TweenAnimationBuilder(tween: Tween(...));

  return Text('$value $value2 $value3');
}

์ด ์ฝ”๋“œ๋Š” ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฝ๊ณ  ํ›„ํฌ์™€ ๊ด€๋ จ์ด ์—†์œผ๋ฉฐ ์ œํ•œ ์‚ฌํ•ญ์ด ์—†์Šต๋‹ˆ๋‹ค.
๊ฐ€๋…์„ฑ ํ–ฅ์ƒ์€ ์ค„ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์„œ์‹ ๋ฐ ๋“ค์—ฌ์“ฐ๊ธฐ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๊ทธ๋Ÿฌ๋‚˜ Builder๊ฐ€ ๋ฃจํŠธ ์œ„์ ฏ์ด ์•„๋‹Œ ๊ฒฝ์šฐ๋Š” ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

์˜ˆ์‹œ:

Widget build(context) {
  return Scaffold(
    body: StreamBuilder(
      stream: stream,
      builder: (context, value) {
        return Consumer<Value2>(
          builder: (context, value2, child) {
            return Text('${value.data} $value2');
          },
        );
      },
    ),
  );
}

์šฐ๋ฆฌ๋Š” ๋‹ค์Œ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Widget build(context) {
  return Scaffold(
    body: {
      final value = keyword StreamBuilder(stream: stream);
      final value2 = keyword Consumer<Value2>();
      return Text('${value.data} $value2');
    }
  );
}

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด ์žฌ์‚ฌ์šฉ์„ฑ ๋ฌธ์ œ์™€ ์–ด๋–ค ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์ด๊ฒƒ์ด ๊ด€๋ จ๋œ ์ด์œ ๋Š” ๋นŒ๋”๊ฐ€ ๊ธฐ์ˆ ์ ์œผ๋กœ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์ œ๋Š” https://github.com/flutter/flutter/issues/51752#issuecomment -669626522 ์ฃผ์„๊ณผ ๊ฐ™์ด _๋งŽ์€_ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•  ๊ณ„ํš์ด๋ผ๋ฉด ์ฝ”๋“œ๋ฅผ ์ฝ๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ์ƒˆ๋กœ์šด ๊ตฌ๋ฌธ์œผ๋กœ ๊ฐ€๋…์„ฑ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋” ๋งŽ์€ ๊ฒƒ์„ ๋นŒ๋”๋กœ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ด ์ฃผ์„์— ์–ธ๊ธ‰๋œ useFilter ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

FilterBuilder(
  debounceDuration: const Duration(seconds: 2),
  builder: (context, filter) {
    return TextField(onChange: (value) => filter.value = value);
  }
)

๊ทธ๋Ÿฐ ๋‹ค์Œ new ํ‚ค์›Œ๋“œ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class ChatScreen extends HookWidget {
  const ChatScreen({Key key}) : super(key: key);

  <strong i="15">@override</strong>
  Widget build(BuildContext context) {
    final filter = keyword FilterBuilder(debounceDuration: const Duration(seconds: 2));
    final userId = keyword Consumer(authProvider).userId;
    final chatId = keyword Consumer(selectedChatProvider);
    final chat = keyword QueryBuilder(ChatQuery(userId: userId, chatId: chatId, filter: filter.value));

    return Column(
      children: [
        Searchbar(onChanged: (value) => filter.value = value),
        Expanded(
          child: ChatList(chat: chat),
        ),
      ],
    );
  }
}

์‚ฌ์šฉ์ž ์ •์˜ ํ›„ํฌ/๋นŒ๋”๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•œ "ํ•จ์ˆ˜๋กœ ์ถ”์ถœ"์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

ํ•จ์ˆ˜์—์„œ Builders ์กฐํ•ฉ์„ ์ถ”์ถœํ•˜์—ฌ ์ด๋Ÿฌํ•œ ํ‚ค์›Œ๋“œ๋กœ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Builder<Chat> ChatBuilder()  {
  final filter = keyword FilterBuilder(debounceDuration: const Duration(seconds: 2));
  final userId = keyword Consumer(authProvider).userId;
  final chatId = keyword Consumer(selectedChatProvider);
  final chat = keyword QueryBuilder(ChatQuery(userId: userId, chatId: chatId, filter: filter.value));

  return Builder(chat);
}

class ChatScreen extends HookWidget {
  const ChatScreen({Key key}) : super(key: key);

  <strong i="21">@override</strong>
  Widget build(BuildContext context) {
    final chat = keyword ChatBuilder();

    return Column(
      children: [
        Searchbar(onChanged: (value) => filter.value = value),
        Expanded(
          child: ChatList(chat: chat),
        ),
      ],
    );
  }
}

๋ถ„๋ช…ํžˆ, ๊ทธ๋Ÿฌํ•œ ๊ตฌ๋ฌธ์˜ ๋ชจ๋“  ์˜๋ฏธ์— ๋Œ€ํ•ด ๋งŽ์€ ์ƒ๊ฐ์ด ์ฃผ์–ด์ง€์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ๊ธฐ๋ณธ์ ์ธ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค.


ํ›„ํฌ๊ฐ€ ์ด ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.
ํ›„ํฌ์˜ ํ•œ๊ณ„๋Š” ์–ธ์–ด ๊ธฐ๋Šฅ์ด ์•„๋‹Œ ํŒจํ‚ค์ง€๋กœ ๊ตฌํ˜„๋˜๊ธฐ ๋•Œ๋ฌธ์— ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ‚ค์›Œ๋“œ๋Š” use keyword StreamBuilder ๊ฐ€ use StreamBuilder ๊ฐ€ ๋˜๋Š” use ์ด๋ฉฐ ๊ถ๊ทน์ ์œผ๋กœ useStream ๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค.

์ด ์ฝ”๋“œ๋Š” ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์˜๊ฒฌ์˜ ๋ฌธ์ œ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ์‚ฌ๋žŒ๋“ค์€ ๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ๋ฒ„์ „์ด ๋” ์ฝ๊ธฐ ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ๋‚˜๋Š” ํ›จ์”ฌ ๋” ๋ช…์‹œ์ ์ธ ๋งˆ๋ฒ•์ด ์—†๋Š” ๋ฒ„์ „์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๋‘ ๋ฒˆ์งธ ์Šคํƒ€์ผ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐ ๋ฐ˜๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋‹ค์Œ ๋‹จ๊ณ„๋Š” @TimWhiting ์˜ ์•ฑ(https://github.com/TimWhiting/local_widget_state_approaches/blob/master/lib/stateful/counter.dart)์—์„œ ์ž‘์—…ํ•˜์—ฌ ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์•ฑ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ๊ฐ€์น˜๋ฅผ ์œ„ํ•ด https://github.com/flutter/flutter/issues/51752#issuecomment -670959424 React์˜ Hooks์— ๋Œ€ํ•œ ์˜๊ฐ๊ณผ ๊ฑฐ์˜ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. Builder ํŒจํ„ด์€ React์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜์—ˆ๋˜ Render Props ํŒจํ„ด๊ณผ ๋™์ผํ•ด ๋ณด์ด์ง€๋งŒ ์œ ์‚ฌํ•˜๊ฒŒ ๊นŠ์€ ํŠธ๋ฆฌ๋กœ ์ด์–ด์กŒ์Šต๋‹ˆ๋‹ค. ๋‚˜์ค‘์— @trueadm ์€ Render Props์— ๋Œ€ํ•œ ๊ตฌ๋ฌธ ์„คํƒ• ์„ ์ œ์•ˆํ–ˆ์œผ๋ฉฐ ๋‚˜์ค‘์— Hooks๋กœ ์ด์–ด์กŒ์Šต๋‹ˆ๋‹ค(๋ถˆํ•„์š”ํ•œ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ ์ œ๊ฑฐ).

`Widget build(context) {
  return ValueListenableBuilder<String>(
    valueListenable: someValueListenable,
    builder: (context, value, _) {
      return StreamBuilder<int>(
        stream: someStream,
        builder: (context, value2) {
          return TweenAnimationBuilder<double>(
            tween: Tween(...),
            builder: (context, value3) {
              return Text('$value $value2 $value3');
            },
          );
        },
      );
    },
  );
}`

๊ฐ€๋…์„ฑ๊ณผ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ๋ฌธ์ œ์ธ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ค์‹œ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  <strong i="8">@override</strong>
  Widget build(context) {
    return ValueListenableBuilder<String>(
      valueListenable: someValueListenable,
      builder: (context, value, _) => buildStreamBuilder(value),
    );
  }

  StreamBuilder<int> buildStreamBuilder(String value) => StreamBuilder<int>(
        stream: someStream,
        builder: (context, value2) => buildTweenAnimationBuilder(value, value2),
      );

  Widget buildTweenAnimationBuilder(String value, AsyncSnapshot<int> value2) =>
      TweenAnimationBuilder<double>(
        duration: Duration(milliseconds: 500),
        tween: Tween(),
        builder: (context, value3, _) => Text('$value $value2 $value3'),
      );

๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์žฌ์‚ฌ์šฉ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์œ„์ ฏ์œผ๋กœ ์ถ”์ถœํ•˜์‹ญ์‹œ์˜ค.

class NewWidget extends StatelessWidget {
  var someValueListenable;

  var someStream;

  <strong i="12">@override</strong>
  Widget build(context) {
    return ValueListenableBuilder<String>(
      valueListenable: someValueListenable,
      builder: (context, value, _) {
        return MyStreamedWidget(value, someStream);
      },
    );
  }
}

class MyStreamedWidget extends StatelessWidget {
  const MyStreamedWidget(
    this.value,
    this.someStream, {
    Key key,
  }) : super(key: key);

  final String value;
  final Stream someStream;

  <strong i="13">@override</strong>
  Widget build(BuildContext context) {
    return StreamBuilder<int>(
      stream: someStream,
      builder: (context, value2) => MyAnimatedWidget(value, value2),
    );
  }
}

class MyAnimatedWidget extends StatelessWidget {
  final String value;
  final AsyncSnapshot<int> value2;

  const MyAnimatedWidget(
    this.value,
    this.value2, {
    Key key,
  }) : super(key: key);

  <strong i="14">@override</strong>
  Widget build(BuildContext context) {
    return TweenAnimationBuilder<double>(
      tween: Tween(),
      builder: (context, value3, _) {
        return Text('$value $value2 $value3');
      },
    );
  }
}

๊ท€ํ•˜์˜ ์˜ˆ์—๋Š” ์ƒˆ๋กœ์šด ํ‚ค์›Œ๋“œ ๋˜๋Š” ๊ธฐ๋Šฅ์„ ๋ณด์ฆํ•˜๋Š” ํ•ญ๋ชฉ์ด ์—†์Šต๋‹ˆ๋‹ค.

๋ฌด์Šจ ๋ง์„ ํ•˜๋ ค๋Š”์ง€ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. '๊ฐ’' ๋ณ€์ˆ˜๋Š” ๋ชจ๋“  ์œ„์ ฏ/ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ „๋‹ฌ๋˜์–ด์•ผ ํ•˜์ง€๋งŒ ์ด๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์„ค๊ณ„ํ•œ ๋ฐฉ๋ฒ•์˜ ๊ฒฐ๊ณผ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋”ฐ๋ผ "๋นŒ๋“œ" ๋ฉ”์„œ๋“œ์™€ ์‚ฌ์šฉ์ž ์ง€์ • ์œ„์ ฏ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ  ๋™์ผํ•œ ๋ณ€์ˆ˜๋ฅผ ์„ธ ๋ฒˆ์˜ ํ˜ธ์ถœ ์ฒด์ธ์— ์ „๋‹ฌํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋Š” ์™ธ๋ถ€ ๋ถ€์ž‘์šฉ(์˜ˆ: InheritedWidgets ๋˜๋Š” (๋ฐ˜)์ „์—ญ ์ƒํƒœ)์— ๊ฐ€๋Šฅํ•œ ํ•œ ์ ๊ฒŒ ์˜์กดํ•  ๋•Œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Rudiksz ์—ฌ๊ธฐ ํ† ๋ก ์— ์•„๋ฌด ๊ฒƒ๋„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•˜๋ฃจ ์ข…์ผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ์™„ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์ „๋žต์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐ๋˜๋ฉด ๊ทธ๋Œ€๋กœ ๊ณ„์† ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋ฉฐ ์ด๋Š” ์ „ํ˜€ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ๊ทผ๋ณธ์ ์ธ ๊ณ ํ†ต์œผ๋กœ ๋ณด๋Š” ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋ถ„๋ช…ํžˆ ์žˆ์œผ๋ฉฐ ์•ž๋’ค๋กœ ์ˆœํ™˜ํ•˜๋Š” ๊ฒƒ์€ ๋ฌด์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๋‹ค์–‘ํ•œ ์ฃผ์žฅ์„ ํ†ตํ•ด ์‚ฌ๋žŒ๋“ค์ด ์›ํ•˜๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๋งˆ์Œ์„ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์„ค๋“ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ํ† ๋ก ์— ์ฐธ์—ฌํ•˜๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ๋“ค์€ ๋ถ„๋ช…ํžˆ Flutter์—์„œ ์ˆ˜๋ฐฑ ๋˜๋Š” ์ˆ˜์ฒœ ์‹œ๊ฐ„์„ ์ž์‹ ์˜ ๋ฒจํŠธ ์•„๋ž˜์— ๋‘๊ณ  ์žˆ์œผ๋ฉฐ, ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์ด์— ๋Œ€ํ•ด ๋™์˜ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์˜๊ฒฌ์˜ ๋ฌธ์ œ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ์‚ฌ๋žŒ๋“ค์€ ๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ๋ฒ„์ „์ด ๋” ์ฝ๊ธฐ ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ๋‚˜๋Š” ํ›จ์”ฌ ๋” ๋ช…์‹œ์ ์ธ ๋งˆ๋ฒ•์ด ์—†๋Š” ๋ฒ„์ „์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๋‘ ๋ฒˆ์งธ ์Šคํƒ€์ผ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐ ๋ฐ˜๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜๊ฒฌ์˜ ๋ฌธ์ œ๋ผ๋ฉด ์ƒ๋‹นํžˆ ํ•œ์ชฝ์œผ๋กœ ์น˜์šฐ์ณ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

  1. ๋‘˜ ๋‹ค ๋งˆ๋ฒ•์ด ์žˆ๋‹ค. ๋‚˜๋Š” ์ด ๋นŒ๋”๋“ค์ด ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฌด์—‡์„ ํ•˜๊ณ  ์žˆ๋Š”์ง€ ๋ฐ˜๋“œ์‹œ ์•Œ์ง€๋Š” ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋น„ ๋งˆ๋ฒ• ๋ฒ„์ „์€ ์ด๋Ÿฌํ•œ ๋นŒ๋” ๋‚ด๋ถ€์— ์‹ค์ œ ์ƒ์šฉ๊ตฌ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. SingleAnimationTIckerProvider ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ Flutter ๊ฐœ๋ฐœ์ž์˜ 95%์—๊ฒŒ๋„ ๋งˆ๋ฒ•์ž…๋‹ˆ๋‹ค.
  2. ํ•˜๋‚˜๋Š” value1 ๋ฐ value2 ์ธ ํŠธ๋ฆฌ์—์„œ ๋‚˜์ค‘์— ์‚ฌ์šฉ๋  ๋งค์šฐ ์ค‘์š”ํ•œ ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ๋‚œ๋…ํ™”ํ•˜๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ๋นŒ๋“œ ๋งจ ์•ž๊ณผ ์ค‘์•™์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ช…ํ™•ํ•œ ๊ตฌ๋ฌธ ๋ถ„์„ / ์œ ์ง€ ๊ด€๋ฆฌ์˜ ์Šน๋ฆฌ์ž…๋‹ˆ๋‹ค.
  3. ํ•˜๋‚˜๋Š” ์œ„์ ฏ ํŠธ๋ฆฌ๊ฐ€ ์‹œ์ž‘๋˜๊ธฐ ์ „์— 6๋‹จ๊ณ„์˜ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์žˆ๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” 0์ž…๋‹ˆ๋‹ค.
  4. ํ•˜๋‚˜๋Š” 5๊ฐœ์˜ ์ˆ˜์ง์„ ์ด๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” 15๊ฐœ์ž…๋‹ˆ๋‹ค.
  5. ํ•˜๋‚˜๋Š” ์‹ค์ œ ์ฝ˜ํ…์ธ  ์กฐ๊ฐ์„ ๋ˆˆ์— ๋„๊ฒŒ ํ‘œ์‹œ(Text())ํ•˜๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ํŠธ๋ฆฌ ์•„๋ž˜๋กœ ์ค‘์ฒฉ๋˜์–ด ์ˆจ๊น๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ๋ช…ํ™•ํ•œ ๊ตฌ๋ฌธ ๋ถ„์„ ์Šน๋ฆฌ.

์ผ๋ฐ˜์ ์ธ ์˜๋ฏธ์—์„œ ๋‚˜๋Š” ์ด๊ฒƒ์ด ์•„๋งˆ๋„ ์ทจํ–ฅ์˜ ๋ฌธ์ œ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Flutter๋Š” ํŠนํžˆ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ผ์ธ ์ˆ˜, ๋“ค์—ฌ์“ฐ๊ธฐ ๋ฐ ์‹ ํ˜ธ: ์žก์Œ ๋น„์œจ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” Dart ์ฝ”๋“œ์—์„œ ์„ ์–ธ์ ์œผ๋กœ ํŠธ๋ฆฌ๋ฅผ ํ˜•์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ ˆ๋Œ€์ ์œผ๋กœ _์‚ฌ๋ž‘_ํ•˜์ง€๋งŒ, ํŠนํžˆ ์—ฌ๋Ÿฌ ๊ณ„์ธต์˜ ๋ž˜ํ•‘๋œ ๋นŒ๋”์— ์˜์กดํ•  ๋•Œ ๋งค์šฐ ์ฝ๊ธฐ ์–ด๋ ต๊ณ  ์žฅํ™ฉํ•œ ์ฝ”๋“œ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๊ฐ€ ์ด ์‹ธ์›€์„ ๊ณ„์†ํ•˜๊ณ  ์žˆ๋Š” Flutter ์ž์ฒด์˜ ๋งฅ๋ฝ์—์„œ ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ์ตœ์ ํ™”๋Š” ๋‹ค์†Œ ๋งŒ์—ฐํ•œ ์ผ๋ฐ˜์ ์ธ ์žฅํ™ฉํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์ •๋ง ํ›Œ๋ฅญํ•œ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ‚ฌ๋Ÿฌ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

TL;DR - Flutter์—์„œ ๋“ค์—ฌ์“ฐ๊ธฐ์™€ ์ค„ ์ˆ˜๋ฅผ ํฌ๊ฒŒ ์ค„์ธ ๋ชจ๋“  ๊ฒƒ์€ ์ผ๋ฐ˜์ ์œผ๋กœ Flutter ๊ณ ์œ ์˜ ์ค„ ์ˆ˜์™€ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ๋ฐฐ๋กœ ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

@Rudiksz ์—ฌ๊ธฐ ํ† ๋ก ์— ์•„๋ฌด ๊ฒƒ๋„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•˜๋ฃจ ์ข…์ผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ์™„ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์ „๋žต์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐ๋˜๋ฉด ๊ทธ๋Œ€๋กœ ๊ณ„์† ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋ฉฐ ์ด๋Š” ์ „ํ˜€ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ธ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ  ์ €์—๊ฒŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ?

์ด๊ฒƒ์„ ๊ทผ๋ณธ์ ์ธ ๊ณ ํ†ต์œผ๋กœ ๋ณด๋Š” ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋ถ„๋ช…ํžˆ ์žˆ์œผ๋ฉฐ ์•ž๋’ค๋กœ ์ˆœํ™˜ํ•˜๋Š” ๊ฒƒ์€ ๋ฌด์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๋‹ค์–‘ํ•œ ์ฃผ์žฅ์„ ํ†ตํ•ด ์‚ฌ๋žŒ๋“ค์ด ์›ํ•˜๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๋งˆ์Œ์„ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์„ค๋“ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ํ† ๋ก ์— ์ฐธ์—ฌํ•˜๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ๋“ค์€ ๋ถ„๋ช…ํžˆ Flutter์—์„œ ์ˆ˜๋ฐฑ ๋˜๋Š” ์ˆ˜์ฒœ ์‹œ๊ฐ„์„ ์ž์‹ ์˜ ๋ฒจํŠธ ์•„๋ž˜์— ๋‘๊ณ  ์žˆ์œผ๋ฉฐ, ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์ด์— ๋Œ€ํ•ด ๋™์˜ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋งž์•„์š” ์ด ๋ง์€ ์ด๋ฏธ ์ˆ˜์—†์ด ๋งž๊ณ  ์ฃฝ์—ˆ์œผ๋‹ˆ ๋”์ด์ƒ ๋Œ“๊ธ€์— ๋‹ต๊ธ€ ๋‹ฌ์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค.

๋นŒ๋”๋Š” ๊ธฐ์ˆ ์ ์œผ๋กœ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์ œ๋Š” ์ฝ”๋“œ๋ฅผ ์ž˜ ์ฝ์ง€ ๋ชปํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๊ทธ๊ฒƒ์„ ์™„๋ฒฝํ•˜๊ฒŒ ์ง„์ˆ ํ•ฉ๋‹ˆ๋‹ค. Flutter ์šฉ์–ด๋กœ ์ƒ๊ฐํ•˜๋ ค๋ฉด ๋‹จ์ผ ๋ผ์ธ ๋นŒ๋”๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ˆ˜์‹ญ ๊ฐœ์˜ ํƒญ๊ณผ ์ค„์ด ํ•„์š”ํ•˜์ง€ ์•Š์ง€๋งŒ ์ผ๋ถ€ ์‚ฌ์šฉ์ž ์ •์˜ ์ƒ์šฉ๊ตฌ๊ฐ€ ์œ„์ ฏ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์—ฐ๊ฒฐ๋˜๋„๋ก ํ—ˆ์šฉํ•˜๋Š” ๋นŒ๋”.

"๋ชจ๋“  ๊ฒƒ์ด ์œ„์ ฏ์ด๋‹ค"๋ผ๋Š” ์ฃผ๋ฌธ์€ ํŠนํžˆ ์—ฌ๊ธฐ์„œ ์ข‹์€ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋นŒ๋”์˜ ๊ด€๋ จ ์ฝ”๋“œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์„ค์ • ์†Œํ’ˆ๊ณผ ๋นŒ๋“œ fxn์— ํ•„์š”ํ•œ ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๋‹จ์ผ ์ค„ ๋ฐ”๊ฟˆ๊ณผ ํƒญ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฌด์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ธ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ  ์ €์—๊ฒŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ?

@Rudiksz ์•„๋ฌด๋„ ์šฐ๋ฆฌ๊ฐ€ Stateful ์œ„์ ฏ์„ ๋ณ€๊ฒฝํ•˜์ž๊ณ  ์ œ์•ˆํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๊ฒฝ์šฐ ํ•ญ์ƒ ํ˜„์žฌ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ƒ๊ฐํ•ด ๋‚ผ ์ˆ˜ ์žˆ๋Š” ์†”๋ฃจ์…˜์ด ๋ฌด์—‡์ด๋“  ๋ณ€๊ฒฝ ์—†์ด Stateful ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์œ ํ˜•์˜ ์œ„์ ฏ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Stateful ์œ„์ ฏ์ด ๋‚˜์˜๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋” ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ์œ„์ ฏ ์ƒํƒœ๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ์œ ํ˜•์˜ ์œ„์ ฏ์„ ์›ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ๋œ ํ•˜๋‚˜์˜ ์ƒํƒœ ๊ฐœ์ฒด ๋Œ€์‹  ์—ฌ๋Ÿฌ ์ƒํƒœ ๊ฐœ์ฒด์™€ ๋ณ„๊ฐœ์ด์ง€๋งŒ ํ•ด๋‹น ์ƒํƒœ ๊ฐœ์ฒด์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋Š” ํ•˜๋‚˜์˜ ๋นŒ๋“œ ๊ธฐ๋Šฅ์„ ํฌํ•จํ•˜๋Š” ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์œผ๋กœ ์ƒ๊ฐํ•˜์‹ญ์‹œ์˜ค. ์ด๋Ÿฐ ์‹์œผ๋กœ initState ๋ฐ dispose ์ด๋ฏธ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ์ผ๋ฐ˜ ์ƒํƒœ ๋น„ํŠธ(ํ•ด๋‹น ์ƒํƒœ์™€ ์—ฐ๊ฒฐ๋œ ์ƒํƒœ ๋…ผ๋ฆฌ์™€ ํ•จ๊ป˜)๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณธ์งˆ์ ์œผ๋กœ ๋ณด๋‹ค ๋ชจ๋“ˆํ™”๋œ ์ƒํƒœ๋กœ, ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์—์„œ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ์ด๊ฒƒ์€ ๊ตฌ์ฒด์ ์ธ ์ œ์•ˆ์ด ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ flutter ์™€ ๊ฐ™์€ ์†”๋ฃจ์…˜์œผ๋กœ ๋ฐ”๋€” ์ˆ˜ ์žˆ์ง€๋งŒ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋‹ค์Œ ๋‹จ๊ณ„๋Š” @TimWhiting ์˜ ์•ฑ(https://github.com/TimWhiting/local_widget_state_approaches/blob/master/lib/stateful/counter.dart)์—์„œ ์ž‘์—…ํ•˜์—ฌ ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์•ฑ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” ๋ณธ์งˆ์ ์œผ๋กœ ์ˆ˜์ฒœ ์ปท์˜ ์ฃฝ์Œ ์ค‘ ํ•˜๋‚˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ ๋ถ€ํ’€๋ฆผ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „์ฒด์—์„œ ๊ฐ€๋…์„ฑ์„ ๊ฐ์†Œ์‹œํ‚ต๋‹ˆ๋‹ค. ์ „์ฒด ํด๋ž˜์Šค๊ฐ€ 100์ค„ ๋ฏธ๋งŒ์ด๊ณ  ์ ˆ๋ฐ˜์ด ์• ๋‹ˆ๋ฉ”์ดํ„ฐ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์ž‘์€ ์œ„์ ฏ์—์„œ ๊ทธ ์˜ํ–ฅ์ด ๊ฐ€์žฅ ์‹ฌํ•˜๊ฒŒ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์˜ˆ์ œ ์ค‘ 30๊ฐœ๋ฅผ ๋ณด๋Š” ๊ฒƒ์ด ๋ฌด์—‡์„ ๋ณด์—ฌ์ค„์ง€ ๋ชจ๋ฅด์ง€๋งŒ 1๊ฐœ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ ์ด๊ฒƒ์˜ ์ฐจ์ด์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<strong i="10">@override</strong>
  Widget build(BuildContext context) {
    final controller = get AnimationController(vsync: this, duration: widget.duration);
    //do stuff
  }

์ด:

  AnimationController _controller;

  <strong i="14">@override</strong>
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: widget.duration);
  }

  <strong i="15">@override</strong>
  void didUpdateWidget(Example oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.duration != oldWidget.duration) {
      _controller.duration = widget.duration;
    }
  }

  <strong i="16">@override</strong>
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  <strong i="17">@override</strong>
  Widget build(BuildContext context) {
    //Do Stuff
  }

์ด๊ฒƒ๋ณด๋‹ค ๋” ์ž˜ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ์—†์Šต๋‹ˆ๋‹ค. ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ ์œ ํ˜• ๊ฐœ์ฒด๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. AnimatorController, FocusController ๋ฐ TextEditingController๋Š” ์•„๋งˆ๋„ ์ผ์ƒ์ ์ธ ์‚ฌ์šฉ์—์„œ ๊ด€๋ฆฌํ•˜๊ธฐ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ด๊ณ  ์„ฑ๊ฐ€์‹  ๊ฒƒ๋“ค์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ œ ์ด ์ค‘ 50๊ฐœ ๋˜๋Š” 100๊ฐœ๋ฅผ ๋‚ด ์ฝ”๋“œ ๊ธฐ๋ฐ˜ ์ „์ฒด์— ๋ฟŒ๋ ธ์Šต๋‹ˆ๋‹ค.

  • ๊ทธ๋ƒฅ ์‚ฌ๋ผ์งˆ ์ˆ˜์žˆ๋Š” ์•ฝ 1000-2000 ์ค„์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์žฌ์ •์˜ ๋˜๋Š” ๋‹ค๋ฅธ ๊ฒƒ์ด ๋ˆ„๋ฝ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์กด์žฌํ•  ํ•„์š”๊ฐ€ ์—†์—ˆ๋˜ ์ˆ˜์‹ญ ๊ฐœ์˜ ๋ฒ„๊ทธ์™€ RTE(๊ฐœ๋ฐœ์˜ ๋‹ค์–‘ํ•œ ์ง€์ ์—์„œ)๊ฐ€ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ์ฐจ๊ฐ€์šด ๋ˆˆ์œผ๋กœ ๋ณผ ๋•Œ ํ•œ ๋ˆˆ์— ๋ณด๊ธฐ์— ํ›จ์”ฌ ๋” ์–ด๋ ค์šด ์œ„์ ฏ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์žฌ์ •์˜ ๊ฐ๊ฐ์„ ์ฝ์–ด์•ผ ํ•˜๋ฉฐ ๋‹จ์ˆœํžˆ ์ƒ์šฉ๊ตฌ๋ผ๊ณ  ๊ฐ€์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก  ์ด๊ฒƒ์„ ์ปค์Šคํ…€ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ํ™•์žฅํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ „์ฒด ๊ฐœ๋…์€ Flutter์—์„œ ๊ทธ๋‹ค์ง€ ๋งค๋ ฅ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ, ๊ด€๋ฆฌ ๋ฐ ํŒŒ๊ดดํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๊ฐ€์‹œ๊ณ  ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ง์ ‘ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ณ  ๋Œ€์‹  ๋งž์ถคํ˜• StatefulWidget/Builder๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋”์— ๊ฐ€๋…์„ฑ ๋ฌธ์ œ๊ฐ€ ์žˆ๊ฑฐ๋‚˜ ์ตœ์†Œํ•œ ํ›จ์”ฌ ๋” ์žฅํ™ฉํ•˜๊ณ  ๊ณต๋ฐฑ์ด ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ์ปจํŠธ๋กค๋Ÿฌ ์œ ํ˜• ๊ฐœ์ฒด๊ฐ€ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ณ  ๋” ๊ฐ•๋ ฅํ•˜๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊นŒ๋‹ค๋กญ๋‹ค

๋„ค, API ๋””์ž์ธ์€ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. ๋‚ด ์ธ์ƒ์— ์˜ค์‹  ๊ฒƒ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ด ์˜ˆ์ œ ์ค‘ 30๊ฐœ๋ฅผ ๋ณด๋Š” ๊ฒƒ์ด ๋ฌด์—‡์„ ๋ณด์—ฌ์ค„์ง€ ๋ชจ๋ฅด์ง€๋งŒ 1๊ฐœ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋„์›€์ด ๋  ๊ฒƒ์€ 30๊ฐœ์˜ ์˜ˆ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ "์Œ, ๋ฌผ๋ก , ์ด ์˜ˆ์ œ์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€๋งŒ _real_ ์˜ˆ์ œ์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์—†์„ ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ •๊ตํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

๋„์›€์ด ๋˜๋Š” ๊ฒƒ์€ 30๊ฐœ์˜ ์˜ˆ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ "๊ธ€์Ž„, ๋ฌผ๋ก , ์ด ์˜ˆ์ œ์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€๋งŒ ์‹ค์ œ ์˜ˆ์ œ์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์—†์„ ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ •๊ตํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

์ด๋ฏธ ๋ช‡ ๋ฒˆ ๋งํ–ˆ์ง€๋งŒ ํ›…์„ ํŒ๋‹จํ•˜๋Š” ๋ฐฉ์‹์€ ๋ถˆ๊ณตํ‰ํ•˜๋‹ค.
Hooks๋Š” ์ด์ „์— ๋ถˆ๊ฐ€๋Šฅํ–ˆ๋˜ ๊ฒƒ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ผ๊ด€๋œ API๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‹ค๋ฅด๊ฒŒ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ฃผ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์€ ๋‚˜๋ฌด๋ฅผ ์˜ค๋ฅด๋Š” ๋Šฅ๋ ฅ์œผ๋กœ ๋ฌผ๊ณ ๊ธฐ๋ฅผ ํŒ๋‹จํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋‹จ์ง€ ํ›„ํฌ๋ฅผ ํŒ๋‹จํ•˜๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ชจ๋“  ์‚ฌ๋žŒ์˜ ์š”๊ตฌ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์†”๋ฃจ์…˜์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ์†”๋ฃจ์…˜์„ ํ‰๊ฐ€ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

(๊ฐ ์ œ์•ˆ์„œ์— ์‹ค์ œ๋กœ ์‹ ์ฒญ์„œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ๋น„๊ตํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์—ฌ๊ธฐ์—์„œ ๋‹ค๋ฅธ ์ œ์•ˆ์„œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ‰๊ฐ€ํ•  ๊ฒƒ์ธ์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ์–ด๋–ค ํ‰๊ฐ€ ์ง€ํ‘œ๋ฅผ ์ œ์•ˆํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?)

์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์„ ํŒ๋‹จํ•˜๋Š” ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์€ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ์•„๋‹™๋‹ˆ๋‹ค(API์˜ ๊ฐ ๊ฐœ๋ณ„ ์‚ฌ์šฉ์€ ์—ฌ๊ธฐ์— ์žˆ๋Š” ์˜ˆ์™€ ๊ฐ™์ด ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค).

์ œ์•ˆ๋œ ์†”๋ฃจ์…˜์„ ํŒ๋‹จํ•ด์•ผ ํ•˜๋Š” ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๊ฒฐ๊ณผ ์ฝ”๋“œ๊ฐ€ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ๋ณด๋‹ค ๊ฐ๊ด€์ ์œผ๋กœ ๋” ๋‚˜์€๊ฐ€์š”?

    • ์‹ค์ˆ˜๋ฅผ ํ”ผํ•ฉ๋‹ˆ๊นŒ?

    • ๋” ์ฝ๊ธฐ ์‰ฌ์šด๊ฐ€์š”?

    • ์“ฐ๊ธฐ๊ฐ€ ๋” ์‰ฝ๋‚˜์š”?

  • ์ฝ”๋“œ๋Š” ์–ผ๋งˆ๋‚˜ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
  • ์ด API๋กœ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

    • ์ผ๋ถ€ ํŠน์ • ๋ฌธ์ œ๋กœ ์ธํ•ด ์ผ๋ถ€ ํ˜œํƒ์„ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๊นŒ?

์ด ๊ทธ๋ฆฌ๋“œ์—์„œ ํ‰๊ฐ€ํ•  ๋•Œ Property / addDispose ์ œ์•ˆ์„œ๋Š” "๊ฒฐ๊ณผ ์ฝ”๋“œ๊ฐ€ ๋” ์ข‹์Šต๋‹ˆ๊นŒ?" ๊ทธ๋Ÿฌ๋‚˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์œ ์—ฐ์„ฑ ๋ชจ๋‘์— ๋Œ€ํ•ด ๋‚ฎ์€ ํ‰๊ฐ€๋ฅผ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

์‹ค์ œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ ์ œ์•ˆ์„ ์‹ค์ œ๋กœ ๋ณด์ง€ ์•Š๊ณ  ์ด๋Ÿฌํ•œ ์งˆ๋ฌธ์— ๋‹ตํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์™œ์š”?

์ด ์ œ์•ˆ์ด ์ง„์ •์œผ๋กœ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์„ ๊ฒช์„ ๊ฒƒ์ž„์„ ์•Œ๊ธฐ ์œ„ํ•ด Property ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด *Builder๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ œ์•ˆ๋œ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์‹œ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ์Šค๋ ˆ๋“œ์— ๋‚˜์—ด๋œ ํ›„ํฌ ๋˜๋Š” React ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๋งŒ๋“  ์ผ๋ถ€ ํ›„ํฌ๋ฅผ ์‹œ๋„ํ•˜๊ณ  ๋‹ค์‹œ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค(์˜จ๋ผ์ธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ›„ํฌ ํŽธ์ง‘์ด ๋งŽ์ด ์žˆ์Œ).

์ด ์ œ์•ˆ์ด ์ง„์ •์œผ๋กœ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์„ ๊ฒช์„ ๊ฒƒ์ž„์„ ์•Œ๊ธฐ ์œ„ํ•ด Property ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

๋ถˆํ–‰ํžˆ๋„, ๋‚˜๋Š” ์—ฌ๊ธฐ์„œ ๋‹น์‹ ์˜ ๋ณธ๋Šฅ์„ ๊ณต์œ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋‹น์‹ ์ด ๊ฐ€์น˜๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•  ๋•Œ๊นŒ์ง€ Property (https://github.com/flutter/flutter/issues/51752#issuecomment-667737471)๊ฐ€ ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค๋Š” ์‚ฌ์‹ค์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด) ๋™์ผํ•œ API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์œ„์ ฏ๊ณผ ๋กœ์ปฌ ์ƒํƒœ์—์„œ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ค๊ธฐ ์ „๊นŒ์ง€๋Š” ์ œ์•ฝ ์กฐ๊ฑด์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค). ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” Property ๋ฒ„์ „๋„ ์ œ๊ณตํ•˜๋ฉด ํ™•์‹คํžˆ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋  ๊ฒƒ์ž…๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ๋‹ค๋ฃจ์ง€ ์•Š๋Š” ์ƒˆ๋กœ์šด ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๋ชฉํ‘œ๊ฐ€ ์—†์œผ๋ฉด ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ๋ชฉํ‘œ๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์†”๋ฃจ์…˜์„ ์„ค๊ณ„ํ•˜๋Š” ๋Œ€์ƒ์ด ๋ฌด์—‡์ธ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด *Builder๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ œ์•ˆ๋œ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์‹œ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ถ„๋ช…ํžˆ _์•„๋ฌด๋„_ ์•„๋‹™๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹น์‹ ์€ OP์—์„œ ํ•˜๋‚˜๋ฅผ ์ฃผ์—ˆ๊ณ , ๋‚ด๊ฐ€ ์ฒซ ๋ฒˆ์งธ Property ์ œ์•ˆ์„ ํ•  ๋•Œ (https://github.com/flutter/flutter/issues/51752#issuecomment-664787791) ๋‹ค์Œ์—์„œ ์„ค๋ช…ํ•˜์ง€ ์•Š์€ ๋ฌธ์ œ๋ฅผ ์ง€์ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋ฆฌ์ง€๋„ ๋นŒ๋”.

์ด ์Šค๋ ˆ๋“œ์— ๋‚˜์—ด๋œ ํ›„ํฌ ๋˜๋Š” React ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๋งŒ๋“  ์ผ๋ถ€ ํ›„ํฌ๋ฅผ ์‹œ๋„ํ•˜๊ณ  ๋‹ค์‹œ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค(์˜จ๋ผ์ธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ›„ํฌ ํŽธ์ง‘์ด ๋งŽ์ด ์žˆ์Œ).

๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์–ด๋””์—์„œ ์‹œ์ž‘ํ•˜๋Š”์ง€ ์ƒ๊ด€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๊ณ  ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ํŠนํžˆ ์ข‹์€ ์˜ˆ๊ฐ€ ์žˆ๋‹ค๋ฉด ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. @TimWhiting ์˜ ์ €์žฅ์†Œ์— ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์š”์ ์€ ๋™์ผํ•œ ๊ฒƒ์„ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•„์ด๋””์–ด๊ฐ€ ์–ด๋””์—์„œ ์™”๋Š”์ง€ ์ƒ๊ด€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋„์›€์ด ๋  ๊ฒƒ์€ 30๊ฐœ์˜ ์˜ˆ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ "์Œ, ๋ฌผ๋ก , ์ด ์˜ˆ์ œ์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€๋งŒ _real_ ์˜ˆ์ œ์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์—†์„ ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ •๊ตํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

์ฝ์„ ์ˆ˜ ์—†๋Š” ๋นŒ๋”๋‚˜ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ƒ์šฉ๊ตฌ ์—†์ด AnimatorController(๋˜๋Š” ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค๋ฅธ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ์ €์žฅ ๊ตฌ์„ฑ ์š”์†Œ)๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๋‹จ์ˆœํ•œ ์š•๊ตฌ๋ณด๋‹ค ๋” ์ •๊ตํ•œ ๊ฒƒ์€ ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฒ”์šฉ ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญ๋œ ๊ฐ€๋…์„ฑ ๋ฐ ๊ฒฌ๊ณ ์„ฑ ์ด์ ์„ ํ•ด๊ฒฐํ•˜๋Š” ์†”๋ฃจ์…˜์ด ์ œ์•ˆ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” _any_ builder๊ฐ€ ํ•  ๊ฒƒ์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” "We need syntax sugar for Builders"๋กœ ์ด๋ฆ„์ด ๋ฐ”๋€Œ๊ณ  ๋™์ผํ•œ ํ† ๋ก ์œผ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

AnimationController ์ƒ์„ฑ ๋ฐ ์‚ญ์ œ์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๋ชจ๋“  ์ธ์ˆ˜๋Š” ๋นŒ๋”๋กœ ์ถ”์ถœ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

Widget build(context) {
  return AnimationControllerBuilder(
    duration: Duration(seconds: 2),
    builder: (context, animationController) {

    }
  );
}

๊ฒฐ๊ตญ ์™„๋ฒฝํ•œ ์˜ˆ๋Š” StreamBuilder๋ฅผ ์™„์ „ํžˆ ๋‹ค์‹œ ๊ตฌํ˜„ํ•˜๊ณ  ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

  • ์ŠคํŠธ๋ฆผ์€ Widget ์—์„œ ์˜ต๋‹ˆ๋‹ค.
  • // InheritedWidget์—์„œ
  • ์ง€์—ญ ์ฃผ์—์„œ

"์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ์ŠคํŠธ๋ฆผ์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Œ"์— ๋Œ€ํ•ด ๊ฐ ๊ฐœ๋ณ„ ์‚ฌ๋ก€๋ฅผ ํ…Œ์ŠคํŠธํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜์‹ญ์‹œ์˜ค.

  • ์ƒˆ ์ŠคํŠธ๋ฆผ์ด ์žˆ๋Š” didUpdateWidget
  • InheritedWidget์ด ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์šฐ๋ฆฌ๋Š” setState๋ฅผ ํ˜ธ์ถœํ–ˆ์Šต๋‹ˆ๋‹ค

์ด๊ฒƒ์€ ํ˜„์žฌ Property ๋˜๋Š” onDispose ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@esDotDev "์š”์ฒญ๋œ ๊ฐ€๋…์„ฑ ๋ฐ ๊ฒฌ๊ณ ์„ฑ ์ด์ "์„ ์—ด๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด๋Ÿฌํ•œ ๊ฐ€๋…์„ฑ๊ณผ ๊ฒฌ๊ณ ์„ฑ ์ด์ ์œผ๋กœ AnimationController๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ œ์•ˆ์„ ํ•˜๋ฉด ์—ฌ๊ธฐ์„œ ๋์ธ๊ฐ€์š”?

@rrousselGit ๋‚˜๋Š” ๋‹น์‹ ์ด ๋‹น์‹ ์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ์ „์— ๋งํ–ˆ๋“ฏ์ด Property๋ฅผ ์˜นํ˜ธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ StreamBuilder๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์—†๋Š” ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค๋ฉด ๊ทธ๊ฒŒ ๋ ๊นŒ์š”? ๋‹น์‹ ์€ ํ–‰๋ณตํ• ๊นŒ์š”?

๊ทธ๋Ÿฌ๋‚˜ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ StreamBuilder๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์—†๋Š” ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค๋ฉด ๊ทธ๊ฒŒ ๋ ๊นŒ์š”? ๋‹น์‹ ์€ ํ–‰๋ณตํ• ๊นŒ์š”?

๋Œ€๋ถ€๋ถ„ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก  ์ด ์†”๋ฃจ์…˜์„ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜๊ณผ ๋น„๊ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์ˆ˜์šฉ ๊ฐ€๋Šฅํ•œ ์ˆ˜์ค€์— ๋„๋‹ฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@esDotDev "์š”์ฒญ๋œ ๊ฐ€๋…์„ฑ ๋ฐ ๊ฒฌ๊ณ ์„ฑ ์ด์ "์„ ์—ด๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ข…์†์„ฑ ๋ฐ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ๋Œ€ํ•œ ์ƒ์šฉ๊ตฌ๋ฅผ ์™„์ „ํžˆ ์บก์Šํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์—์„œ ๊ฒฌ๊ณ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰. ๋‚˜๋Š” fetchUser์—๊ฒŒ ๋งค๋ฒˆ id๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋‹ค์‹œ ๋นŒ๋“œํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ๋‚ด๋ถ€์ ์œผ๋กœ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Animation์ด ๋ถ€๋ชจ ์œ„์ ฏ์ด ํ๊ธฐ๋  ๋•Œ๋งˆ๋‹ค ์Šค์Šค๋กœ ํ๊ธฐํ•˜๋„๋ก ์ง€์‹œํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. (Property๊ฐ€ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์™„์ „ํžˆ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค) ์ด๊ฒƒ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ ๊ธฐ๋ฐ˜ ์ „์ฒด์—์„œ ๋ฐ˜๋ณต์ ์ธ ์ž‘์—…์— ๋Œ€ํ•œ ์‹ค์ˆ˜๋ฅผ ์ €์ง€๋ฅด๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค(ํ˜„์žฌ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฃผ์š” ์ด์  ์ค‘ ํ•˜๋‚˜).

๊ฐ€๋…์„ฑ์€ ๋“ค์—ฌ์“ฐ๊ธฐ๋˜์ง€ ์•Š์€ ํ•œ ์ค„์˜ ์ฝ”๋“œ๋กœ ์ƒํƒœ ์ €์žฅ ํ•ญ๋ชฉ์„ ์–ป์„ ์ˆ˜ ์žˆ๊ณ  ํ•ด๋‹น ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ๋ณ€์ˆ˜๊ฐ€ ํ˜ธ์ด์ŠคํŠธ๋˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œ์‹œ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@esDotDev ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ AnimationController๋ฅผ ์ด๋Ÿฌํ•œ ๊ฐ€๋…์„ฑ๊ณผ ๊ฒฌ๊ณ ์„ฑ ์ด์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ์ œ์•ˆ์„ ํ•œ๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ ๋์ธ๊ฐ€์š”?

๊ตฌ์ฒด์ ์œผ๋กœ AnimationController ๋ฒˆํ˜ธ๋ฅผ ์˜๋ฏธํ•œ๋‹ค๋ฉด. AnimationController/FocusController/TextEditingController์™€ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•œ๋‹ค๋ฉด ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ์ •์˜๋œ ์ˆ˜๋ช…์ด ์žˆ๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์™€ ๊ฐ™์€ API๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€

์ด๊ฒƒ์€ ์ค‘์š”ํ•œ ์˜คํ•ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ›„ํฌ์˜ ์ˆ˜๋ช…์€ ์ •์˜์— ๋”ฐ๋ผ ํ•˜์œ„ ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์€ ๊ทธ๊ฒƒ๋“ค์„ "์‚ฌ์šฉ"ํ•˜๋Š” ๊ตญ๊ฐ€์˜ ์ผ์ƒ ๋™์•ˆ _ํ•ญ์ƒ_ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๋” ๋ช…ํ™•ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ตฌ๋ฌธ์ด ์ด์ƒํ•˜๊ณ  ์ƒ์†Œํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ช…ํ™•์„ฑ์ด ๋ถ€์กฑํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

TweenAnimationBuilder()์˜ ์ˆ˜๋ช…๋„ ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค. ๋ถ€๋ชจ๊ฐ€ ๋– ๋‚˜๋ฉด ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ํ•˜์œ„ ์œ„์ ฏ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•˜์œ„ ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์€ ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ธ ์ƒํƒœ "๊ตฌ์„ฑ ์š”์†Œ"์ด๋ฉฐ, ์‰ฝ๊ฒŒ ์กฐํ•ฉํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹Œ ๊ธฐ๋Šฅ์ด ์„ ์–ธ๋œ ์ƒํƒœ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐ”์ธ๋”ฉ๋˜๊ธฐ๋ฅผ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜๋ช…์„ ๋ช…์‹œ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@esDotDev

๋“ฑ

๋” ์ž์„ธํ•˜๊ฒŒ ์–˜๊ธฐํ•ด ์ฃผ ์‹œ๊ฒ ์–ด์š”? (์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ๋ชจ๋“  ๊ธฐ๋ฐ˜์„ ๋‹ค๋ฃจ๋Š” ๋ฐ๋ชจ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ์ œ์•ˆํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ๊ณ„์†ํ•ด์„œ ์ด๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.) ๊ตฌ์„ฑ์ด ๋ณ€๊ฒฝ๋˜์–ด ์ž๋™์œผ๋กœ ์‚ญ์ œ๋˜์ง€ ์•Š๋Š” ํ•œ ์ดˆ๊ธฐํ™” ํ”„๋กœ๊ทธ๋žจ์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ ์™ธ์— ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ํ˜ธ์ŠคํŠธ ์š”์†Œ๊ฐ€ ์‚ญ์ œ๋  ๋•Œ ํ• ๋‹น๋œ ๋ฆฌ์†Œ์Šค?

TextEditingController์™€ ์œ ์‚ฌํ•œ ๊ฐ์ฒด

๋” ์ž์„ธํ•˜๊ฒŒ ์–˜๊ธฐํ•ด ์ฃผ ์‹œ๊ฒ ์–ด์š”? TextEditingController๋Š” ์–ด๋–ค ๋ฉด์—์„œ AnimationController๋ณด๋‹ค ๋” ์ •๊ตํ•ฉ๋‹ˆ๊นŒ?


@rrousselGit

๊ทธ๋Ÿฌ๋‚˜ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ StreamBuilder๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์—†๋Š” ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค๋ฉด ๊ทธ๊ฒŒ ๋ ๊นŒ์š”? ๋‹น์‹ ์€ ํ–‰๋ณตํ• ๊นŒ์š”?

๋Œ€๋ถ€๋ถ„ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋“ค์—ฌ์“ฐ๊ธฐ ์—†์ด StreamBuilder๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค.

Widget build(context) {
  var result = Text('result:');
  var builder1 = (BuildContext context, AsyncSnapshot<int> snapshot) {
    return Row(children: [result, Text(snapshot.data)]);
  };
  result = StreamBuilder(stream: _stream1, builder: builder1);
  var builder2 = (BuildContext context, AsyncSnapshot<int> snapshot) {
    return Column(children: [result, Text(snapshot.data)]);
  };
  result = StreamBuilder(stream: _stream2, builder: builder2);
}

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด ๋‹ค๋ฅธ ์ œ์•ฝ ์กฐ๊ฑด์„ ์œ„๋ฐ˜ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์ „์— ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ „์ฒด ์„ค๋ช…์ด ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ๋™์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

๋นŒ๋”๊ฐ€ @Hixie๋ฅผ ๊ฐ–๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ์ œ์•ฝ ์กฐ๊ฑด์€

๋” ์ž์„ธํ•˜๊ฒŒ ์–˜๊ธฐํ•ด ์ฃผ ์‹œ๊ฒ ์–ด์š”? TextEditingController๋Š” ์–ด๋–ค ๋ฉด์—์„œ AnimationController๋ณด๋‹ค ๋” ์ •๊ตํ•ฉ๋‹ˆ๊นŒ?

์•„๋‹ˆ์š”, ํ•˜์ง€๋งŒ init/dispose์—์„œ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์†์„ฑ์— ๋ฐ”์ธ๋”ฉ๋˜๋ฉฐ ํŠน์ • ์ƒ์šฉ๊ตฌ๋ฅผ ์บก์Šํ™”ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

@esDotDev ๊ทธ๋ž˜์„œ ๋นŒ๋”์™€ ๊ฐ™์€ ๊ฒƒ์„ ์›ํ•˜์ง€๋งŒ ๋“ค์—ฌ์“ฐ๊ธฐ ์—†์ด ํ•œ ์ค„๋กœ(์•„๋งˆ๋„ ๋นŒ๋” ์ฝœ๋ฐฑ ์ž์ฒด ์ œ์™ธ)? ๋‚ด๊ฐ€ ๋ฐฉ๊ธˆ ๊ฒŒ์‹œํ•œ ์˜ˆ์ œ(https://github.com/flutter/flutter/issues/51752#issuecomment-671004483)๋Š” ์˜ค๋Š˜๋‚  ๋นŒ๋”์—์„œ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฏ€๋กœ ์•„๋งˆ๋„ ๊ทธ ์ด์ƒ์˜ ์ถ”๊ฐ€ ์ œ์•ฝ์ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

(FWIW, ๋นŒ๋” ๋˜๋Š” ๋นŒ๋”์™€ ๊ฐ™์€ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ•œ ์ค„์— ์žˆ๋Š” ๊ฒƒ์ด ์ข‹์€ ์†”๋ฃจ์…˜์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ ๋ฐ์ดํ„ฐ ์œ ํ˜•์— ์ž์ฒด ๋นŒ๋”๊ฐ€ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ฆ‰์„์—์„œ ๋นŒ๋“œํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์—†์Šต๋‹ˆ๋‹ค. .)

(FWIW, ๋นŒ๋” ๋˜๋Š” ๋นŒ๋”์™€ ๊ฐ™์€ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ•œ ์ค„์— ์žˆ๋Š” ๊ฒƒ์ด ์ข‹์€ ์†”๋ฃจ์…˜์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ ๋ฐ์ดํ„ฐ ์œ ํ˜•์— ์ž์ฒด ๋นŒ๋”๊ฐ€ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ฆ‰์„์—์„œ ๋นŒ๋“œํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์—†์Šต๋‹ˆ๋‹ค. .)

์ด๊ฒŒ ๋ฌด์Šจ ๋œป์ธ์ง€ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ ๋‹ค์‹œ ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๐Ÿ™

Animations์šฉ โ€‹โ€‹AnimationBuilder์™€ Streams์šฉ StreamBuilder ๋“ฑ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ผ ๋นŒ๋”๋ฅผ ๊ฐ€์ง€๊ณ  StatefulWidget์„ ์ƒ์„ฑํ•  ๋•Œ "์—ฌ๊ธฐ์— ์ƒˆ ๋นŒ๋”๋ฅผ ์–ป๋Š” ๋ฐฉ๋ฒ•, ํ๊ธฐํ•˜๋Š” ๋ฐฉ๋ฒ•, ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•˜๋Š” ๋Œ€์‹ .

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด ๋‹ค๋ฅธ ์ œ์•ฝ ์กฐ๊ฑด์„ ์œ„๋ฐ˜ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์ „์— ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ „์ฒด ์„ค๋ช…์ด ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ๋™์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๊ถ๊ทน์ ์œผ๋กœ ์—ฌ๊ธฐ์˜ ๋ชฉํ‘œ์ธ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๋ถ„๋ช…ํžˆ ์œ„๋ฐ˜ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์šฐ๋ฆฌ ๋ชจ๋‘๋Š” ๋ฐฑ๋งŒ ๊ฐœ์˜ ํŠน์ • ์œ ํ˜•์˜ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์˜์›ํžˆ ์ค‘์ฒฉํ•˜๊ณ  ํ•˜๋ฃจ๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์š”์ฒญ๋˜๋Š” ๊ฒƒ์ด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

Widget build(context) {
   var snapshot1 = get AsyncSnapshot<int>(stream1);
   var snapshot2 = get AsyncSnapshot<int>(stream2);
   return Column(children: [Text(snapshot1.data), Text(snapshot2.data)]);
}

์ด๊ฒƒ์ด ๋ชจ๋“  ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์ŠคํŠธ๋ฆผ์ด ์šฐ๋ฆฌ๋ฅผ ์œ„ํ•ด ์ƒ์„ฑ๋˜๊ณ , ์ŠคํŠธ๋ฆผ์ด ์šฐ๋ฆฌ๋ฅผ ์œ„ํ•ด ํ๊ธฐ๋˜๊ณ , ์šฐ๋ฆฌ๋Š” ๋ฐœ์„ ๋“ค์—ฌ๋†“์„ ์ˆ˜ ์—†์œผ๋ฉฐ ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

Animations์šฉ โ€‹โ€‹AnimationBuilder์™€ Streams์šฉ StreamBuilder ๋“ฑ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋ฌธ์ œ๋กœ ๋ณด์ง€ ์•Š๋Š”๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ RestorableInt ๋Œ€ RestorableString ๋Œ€ RestorableDouble์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ œ๋„ค๋ฆญ์€ ๋‹ค์Œ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

GenericBuilder<Stream<int>>(
  create: (ref) {
    var controller = StreamController<int>();
    ref.onDispose(controller.close);
    return controller.stream;
  }
  builder: (context, Stream<int> stream) {

  }
)

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Flutter ๋˜๋Š” Dart๋Š” ์‹ค์ œ๋กœ ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ Disposable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@esDotDev

์š”์ฒญ๋˜๋Š” ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋‚˜์—ดํ•œ ๊ฝค ํ•ฉ๋ฆฌ์ ์ธ ์ œ์•ฝ ์กฐ๊ฑด(์˜ˆ: @Rudiksz)์„ ์œ„๋ฐ˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋นŒ๋“œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋™์•ˆ ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

@rrousselGit

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋ฌธ์ œ๋กœ ๋ณด์ง€ ์•Š๋Š”๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ RestorableInt ๋Œ€ RestorableString ๋Œ€ RestorableDouble์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  AnimationBuilder์™€ StreamBuilder ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ ๋ถˆํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ œ๋„ค๋ฆญ ๋นŒ๋”

๊ทธ๊ฒƒ์€ ๋‚ด๊ฐ€ Property์— ๋Œ€ํ•ด ์ œ์•ˆํ•œ ๊ฒƒ๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ, ๊ฑฐ๊ธฐ์—์„œ ๊ท€ํ•˜์˜ ์šฐ๋ ค ์‚ฌํ•ญ์„ ์ดํ•ดํ–ˆ๋‹ค๋ฉด ๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด์ „์— ๋ˆ„๊ตฐ๊ฐ€ StreamBuilder๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์—†๋Š” ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค๋ฉด ๋งŒ์กฑํ•  ๊ฒƒ์ด๋ผ๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ์‹œ๋„์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์œผ์…จ์Šต๋‹ˆ๋‹ค(https://github.com/flutter/flutter/issues/51752#issuecomment-671004483). ๊ทธ ์†”๋ฃจ์…˜์— ๋งŒ์กฑํ•˜์‹ญ๋‹ˆ๊นŒ?

@esDotDev

์š”์ฒญ๋˜๋Š” ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋‚˜์—ดํ•œ ๊ฝค ํ•ฉ๋ฆฌ์ ์ธ ์ œ์•ฝ ์กฐ๊ฑด(์˜ˆ: @Rudiksz)์„ ์œ„๋ฐ˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋นŒ๋“œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋™์•ˆ ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

์ด ์ฝ”๋“œ๊ฐ€ ๋นŒ๋“œ์— ์žˆ๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€

  1. ๋‚ด ํŠธ๋ฆฌ๋ฅผ ๋“ค์—ฌ์“ฐ๊ฑฐ๋‚˜ ๋งŽ์€ ์ค„์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.
  2. ์ด ํ•ญ๋ชฉ๊ณผ ๊ด€๋ จ๋œ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ฝ”๋“œ๊ฐ€ ์บก์Šํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋†€๋ผ์šด ๊ฒƒ์ž…๋‹ˆ๋‹ค:

AsyncSnapshot<int> snapshot1 = createLifecycleState(widget.stream1);
AsyncSnapshot<int> snapshot2 = createLifecycleState(widget.stream2);
AniamtorController animator = createLifecycleState(duration: Duration(seconds: 1), (a)=>a.forward());

Widget build(context) {
   return Opacity(opacity: animator.value, child: Column(children: [Text(snapshot1.data), Text(snapshot2.data)]));
}

๋˜๋Š” ๊ฐ„๊ฒฐํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์—ฌ์ „ํžˆ ์ฝ๊ธฐ ์‰ฝ๊ณ  ์ง์ ‘ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์žฅํ™ฉํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

AsyncSnapshot<int> stream1;
AsyncSnapshot<int> stream2;
<strong i="18">@override</strong> 
void initState(){
    snapshot1 = createLifecycleState(widget.stream1);
    snapshot2 = createLifecycleState(widget.stream2);
   super.initState();
}

Widget build(context) {
   return Column(children: [Text(snapshot1.data), Text(snapshot2.data)]);
}

์™œ ์šฐ๋ฆฌ๊ฐ€ ๊ณ„์† ์žฅํ™ฉํ•˜๊ฒŒ ๋Œ์•„๊ฐ€๋Š”์ง€ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ ๋ฌธ์ œ๋Š” ์žฌ์‚ฌ์šฉ์„ฑ ๋Œ€ ๊ฐ€๋…์„ฑ ๋Œ€ ์œ ์—ฐ์„ฑ์ด๋ผ๊ณ  ์—ฌ๋Ÿฌ ๋ฒˆ ๋ช…์‹œ์ ์œผ๋กœ ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

์†”๋ฃจ์…˜ https://github.com/flutter/flutter/issues/51752#issuecomment -671000137 ๋ฐ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค https://github.com/flutter/flutter/issues/51752#issuecomment ๋ฅผ ํ‰๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ๊ทธ๋ฆฌ๋“œ๋„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. 671002248


์ด์ „์— ๋ˆ„๊ตฐ๊ฐ€ StreamBuilder๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์—†๋Š” ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค๋ฉด ๋งŒ์กฑํ•  ๊ฒƒ์ด๋ผ๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ์‹œ๋„์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์œผ์…จ์Šต๋‹ˆ๋‹ค(#51752(๋Œ“๊ธ€)). ๊ทธ ์†”๋ฃจ์…˜์— ๋งŒ์กฑํ•˜์‹ญ๋‹ˆ๊นŒ?

์ด๋Š” ํ—ˆ์šฉ ๊ฐ€๋Šฅํ•œ ์ตœ์†Œ ์ˆ˜์ค€์˜ ์œ ์—ฐ์„ฑ์— ๋„๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

https://github.com/flutter/flutter/issues/51752#issuecomment -671000137์— ๋”ฐ๋ผ ํ‰๊ฐ€ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๊ฒฐ๊ณผ ์ฝ”๋“œ๊ฐ€ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ๋ณด๋‹ค ๊ฐ๊ด€์ ์œผ๋กœ ๋” ๋‚˜์€๊ฐ€์š”?

    • ์‹ค์ˆ˜๋ฅผ ํ”ผํ•ฉ๋‹ˆ๊นŒ?

      _๊ธฐ๋ณธ ๊ตฌ๋ฌธ(ํ•ดํ‚น ์—†๋Š” StreamBuilder)์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ด ์†”๋ฃจ์…˜์€ ์‹ค์ˆ˜๋ฅผ ํ”ผํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ผ๋ถ€๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค_ โŒ

    • ๋” ์ฝ๊ธฐ ์‰ฌ์šด๊ฐ€์š”?

      _๋ถ„๋ช…ํžˆ ๋” ์ฝ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค_ โŒ

    • ์“ฐ๊ธฐ๊ฐ€ ๋” ์‰ฝ๋‚˜์š”?

      _์“ฐ๊ธฐ๊ฐ€ ์‰ฝ์ง€ ์•Š์•„์š”_ โŒ

  • ์ฝ”๋“œ๋Š” ์–ผ๋งˆ๋‚˜ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _StreamBuilder๋Š” Widget/State/life-cycles์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด ํŒจ์Šค_ โœ…
  • ์ด API๋กœ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _์ปค์Šคํ…€ ๋นŒ๋”๋ฅผ ๋งŒ๋“ค๊ณ  ์ด ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฒˆ ํŒจ์Šค_. โœ…
  • ์ผ๋ถ€ ํŠน์ • ๋ฌธ์ œ๋กœ ์ธํ•ด ์ผ๋ถ€ ํ˜œํƒ์„ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๊นŒ?
    _์•„๋‹ˆ์š”, ๊ตฌ๋ฌธ์€ ๋น„๊ต์  ์ผ๊ด€์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค_. โœ…
  1. ์ด ๊ธฐ๋Šฅ IMO๋Š” ์˜ˆ๋ฅผ ๋“ค์–ด LayoutBuilder๋ฅผ ํฌํ•จํ•œ ๋ชจ๋“  ๋นŒ๋” ์œ„์ ฏ์œผ๋กœ ํ™•์žฅ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๋ฆฌ์Šค๋‹์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์•ผ 10x ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ๋ฆฌํ”„์— ์ „๋‹ฌํ•˜์—ฌ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๊ฑฐ๋‚˜ flutter๊ฐ€ ๋นŒ๋”์—์„œ ์–ป์€ ๊ฐ’์„ ํŠธ๋ฆฌ์˜ ์–ด๋Š ๋ถ€๋ถ„์—์„œ ์‚ฌ์šฉํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  3. ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํ›„ํฌ๋ณด๋‹ค ํ›จ์”ฌ ๋” ์žฅํ™ฉํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  4. ์ด๋ฅผ ์ œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ํ™•์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  5. ๋””๋ฒ„๊น… ๋„์šฐ๋ฏธ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ์œ„์ ฏ ์ค‘ ํ•˜๋‚˜์— ์ค‘๋‹จ์ ์„ ๋„ฃ์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ ๋‚ด์—์„œ ์ค‘๋‹จ์ ์— ๋„๋‹ฌํ•˜๋ฉด ๋นŒ๋” ์ค‘ ํ•˜๋‚˜๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— IDE๋Š” ์‚ฌ์šฉ๋œ ๊ฐ ๋นŒ๋”์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Widget build(context) {
   // this builder is not highlighted, but you can hover over it to see how often it rebuilds, how heavy were those rebuilds, and when was the last rebuild
   var snapshot1 = keyword StreamBuilder(stream1);
   // this builder will be highlighted because it triggered the rebuild
   var constraints = keyword LayoutBuilder(); 

   // <-- I had a breakpoint here and parent constraint changed, breakpoints got reached.
   return Column(children: [Text(snapshot1.data), Text(snapshot2.data)]);
}

๋˜ํ•œ @Hixie

์ด๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋‚˜์—ดํ•œ ๊ฝค ํ•ฉ๋ฆฌ์ ์ธ ์ œ์•ฝ ์กฐ๊ฑด(์˜ˆ: @Rudiksz)์„ ์œ„๋ฐ˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋นŒ๋“œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋™์•ˆ ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ด๋ฏธ *Builders๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•”์‹œ์ ์œผ๋กœ ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ๋“ค์„ ๋“ค์—ฌ ์“ฐ๊ธฐ ์œ„ํ•ด ๋ฌธ๋ฒ• ์„คํƒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. async/wait ๋ฐ future์™€ ๋งค์šฐ ์œ ์‚ฌํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@esDotDev ์„ค๋ช…ํ•˜๋Š” ๋‚ด์šฉ์€ ์ด์ „์— ๋‚ด๊ฐ€ Property๋กœ ์ œ์•ˆํ•œ ๋‚ด์šฉ๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: https://github.com/flutter/flutter/issues/51752#issuecomment-664787791 ๋˜๋Š” https://github.com/flutter/flutter/ ์ฐธ์กฐ). ๋ฌธ์ œ/51752#issuecomment-667737471). ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ์†”๋ฃจ์…˜์ด ํŒจํ‚ค์ง€๋กœ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ฆ‰, ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋ฉด ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์–ด๋–ค ๋ณ€๊ฒฝ์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@rrousselGit Shawn๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ

๊ทธ๋ฆฌ๋“œ์— ๋Œ€ํ•œ ๋ฌธ์ œ๋Š” ์ง€๊ธˆ๊นŒ์ง€ ์†”๋ฃจ์…˜์— ์ ์šฉํ•˜๋ฉด ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๊ณผ๋Š” ๋งค์šฐ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๊ฐ€์ •ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์Šคํ…Œ์ดํŠธํ’€ ์œ„์ ฏ

  • ๊ฒฐ๊ณผ ์ฝ”๋“œ๊ฐ€ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ๋ณด๋‹ค ๊ฐ๊ด€์ ์œผ๋กœ ๋” ๋‚˜์€๊ฐ€์š”?

    • ์‹ค์ˆ˜๋ฅผ ํ”ผํ•ฉ๋‹ˆ๊นŒ?

      _๊ธฐ๋ณธ ๊ตฌ๋ฌธ๊ณผ ๋™์ผํ•˜๋ฉฐ ํŠน๋ณ„ํžˆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค._ ๐Ÿ”ท

    • ๋” ์ฝ๊ธฐ ์‰ฌ์šด๊ฐ€์š”?

      _๋˜‘๊ฐ™์•„์„œ ๋˜‘๊ฐ™์ด ๊ฐ€๋…์„ฑ์ด ์ข‹๊ณ  ๊ฐ€๋…์„ฑ์ด ์ข‹์Šต๋‹ˆ๋‹ค._ ๐Ÿ”ท

    • ์“ฐ๊ธฐ๊ฐ€ ๋” ์‰ฝ๋‚˜์š”?

      _๋˜‘๊ฐ™์•„์„œ ๋˜‘๊ฐ™์ด ์“ฐ๊ธฐ ์‰ฝ๊ณ , ์ ๋‹นํžˆ ์‰ฝ๋„ค์š”._ ๐Ÿ”ท

  • ์ฝ”๋“œ๋Š” ์–ผ๋งˆ๋‚˜ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _์žฌ์‚ฌ์šฉํ•  ์ฝ”๋“œ๊ฐ€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค._ โœ…
  • ์ด API๋กœ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _๊ธฐ๋ณธ์ž…๋‹ˆ๋‹ค._ ๐Ÿ”ท
  • ์ผ๋ถ€ ํŠน์ • ๋ฌธ์ œ๋กœ ์ธํ•ด ์ผ๋ถ€ ํ˜œํƒ์„ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๊นŒ?
    _๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค._ โœ…

์†์„ฑ์— ๋Œ€ํ•œ ๋ณ€ํ˜•

  • ๊ฒฐ๊ณผ ์ฝ”๋“œ๊ฐ€ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ๋ณด๋‹ค ๊ฐ๊ด€์ ์œผ๋กœ ๋” ๋‚˜์€๊ฐ€์š”?

    • ์‹ค์ˆ˜๋ฅผ ํ”ผํ•ฉ๋‹ˆ๊นŒ?

      _์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ์˜ฎ๊ธฐ์ง€๋งŒ ํŠน๋ณ„ํžˆ ์‹ค์ˆ˜๋ฅผ ์ค„์ด์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค._ ๐Ÿ”ท

    • ๋” ์ฝ๊ธฐ ์‰ฌ์šด๊ฐ€์š”?

      _์ดˆ๊ธฐํ™” ์ฝ”๋“œ์™€ ์ •๋ฆฌ ์ฝ”๋“œ ๋ฐ ๊ธฐํƒ€ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ฝ”๋“œ๋ฅผ ๊ฐ™์€ ์œ„์น˜์— ๋‘๋ฏ€๋กœ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค._ โŒ

    • ์“ฐ๊ธฐ๊ฐ€ ๋” ์‰ฝ๋‚˜์š”?

      _์ดˆ๊ธฐํ™” ์ฝ”๋“œ์™€ ํด๋ฆฐ์—… ์ฝ”๋“œ, ๊ธฐํƒ€ ๋ผ์ดํ”„์‚ฌ์ดํด ์ฝ”๋“œ๊ฐ€ ํ˜ผ์žฌ๋˜์–ด ์žˆ์–ด์„œ ์“ฐ๊ธฐ๊ฐ€ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค._ โŒ

  • ์ฝ”๋“œ๋Š” ์–ผ๋งˆ๋‚˜ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _StatefulWidget๋งŒํผ ์ •ํ™•ํžˆ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค๋ฅธ ์žฅ์†Œ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค._ โœ…
  • ์ด API๋กœ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _StatefulWidget์— ๋Œ€ํ•œ ๊ตฌ๋ฌธ ์„คํƒ•์ด๋ฏ€๋กœ ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค._ ๐Ÿ”ท
  • ์ผ๋ถ€ ํŠน์ • ๋ฌธ์ œ๋กœ ์ธํ•ด ์ผ๋ถ€ ํ˜œํƒ์„ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๊นŒ?
    _์„ฑ๋Šฅ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์•ฝ๊ฐ„ ์ €ํ•˜๋ฉ๋‹ˆ๋‹ค._ โŒ

๋นŒ๋”์˜ ๋ณ€ํ˜•

  • ๊ฒฐ๊ณผ ์ฝ”๋“œ๊ฐ€ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ๋ณด๋‹ค ๊ฐ๊ด€์ ์œผ๋กœ ๋” ๋‚˜์€๊ฐ€์š”?

    • ์‹ค์ˆ˜๋ฅผ ํ”ผํ•ฉ๋‹ˆ๊นŒ?

      _๊ธฐ๋ณธ์ ์œผ๋กœ StatefulWidget ์†”๋ฃจ์…˜์ด์ง€๋งŒ ์ œ์™ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ˆ˜๋Š” ๊ฑฐ์˜ ๋™์ผํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค._ ๐Ÿ”ท

    • ๋” ์ฝ๊ธฐ ์‰ฌ์šด๊ฐ€์š”?

      _๋นŒ๋“œ ๋ฐฉ๋ฒ•์€ ๋” ๋ณต์žกํ•˜๊ณ  ๋‚˜๋จธ์ง€ ๋…ผ๋ฆฌ๋Š” ๋‹ค๋ฅธ ์œ„์ ฏ์œผ๋กœ ์ด๋™ํ•˜๋ฏ€๋กœ ๊ฑฐ์˜ ๋™์ผํ•ฉ๋‹ˆ๋‹ค._ ๐Ÿ”ท

    • ์“ฐ๊ธฐ๊ฐ€ ๋” ์‰ฝ๋‚˜์š”?

      _์ฒ˜์Œ ์ž‘์„ฑํ•˜๊ธฐ(๋นŒ๋” ์œ„์ ฏ ๋งŒ๋“ค๊ธฐ)๊ฐ€ ๋” ์–ด๋ ต๊ณ  ๊ทธ ์ดํ›„์—๋Š” ์•ฝ๊ฐ„ ๋” ์‰ฌ์›Œ์ง€๋ฏ€๋กœ ๊ฑฐ์˜ ๋™์ผํ•ฉ๋‹ˆ๋‹ค._ ๐Ÿ”ท

  • ์ฝ”๋“œ๋Š” ์–ผ๋งˆ๋‚˜ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _StatefulWidget๋งŒํผ ์ •ํ™•ํžˆ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค๋ฅธ ์žฅ์†Œ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค._ โœ…
  • ์ด API๋กœ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _ ์ด๊ฒƒ์€ StatefulWidget์˜ ๊ตฌ๋ฌธ ์„คํƒ•์ด๋ฏ€๋กœ ๋Œ€๋ถ€๋ถ„ ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ์ธก๋ฉด์—์„œ๋Š” ์‹ค์ œ๋กœ ๋” ์ข‹์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ข…์†์„ฑ ๋ณ€๊ฒฝ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ฝ”๋“œ์˜ ์–‘์ด ์ค„์–ด๋“ญ๋‹ˆ๋‹ค._ โœ…
  • ์ผ๋ถ€ ํŠน์ • ๋ฌธ์ œ๋กœ ์ธํ•ด ์ผ๋ถ€ ํ˜œํƒ์„ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๊นŒ?
    _๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค._ โœ…

ํ›„ํฌ์™€ ๊ฐ™์€ ์†”๋ฃจ์…˜

  • ๊ฒฐ๊ณผ ์ฝ”๋“œ๊ฐ€ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ๋ณด๋‹ค ๊ฐ๊ด€์ ์œผ๋กœ ๋” ๋‚˜์€๊ฐ€์š”?

    • ์‹ค์ˆ˜๋ฅผ ํ”ผํ•ฉ๋‹ˆ๊นŒ?

      _์ž˜๋ชป๋œ ํŒจํ„ด(์˜ˆ: ๋นŒ๋“œ ๋ฉ”์„œ๋“œ์˜ ๊ตฌ์„ฑ)์„ ์กฐ์žฅํ•˜๊ณ  ์กฐ๊ฑด๋ฌธ๊ณผ ํ•จ๊ป˜ ์‹ค์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์œ„ํ—˜์ด ์žˆ์Šต๋‹ˆ๋‹ค._ โŒ

    • ๋” ์ฝ๊ธฐ ์‰ฌ์šด๊ฐ€์š”?

      _๋นŒ๋“œ ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์•Œ์•„์•ผ ํ•  ๊ฐœ๋…์˜ ์ˆ˜๋ฅผ ๋Š˜๋ฆฝ๋‹ˆ๋‹ค._ โŒ

    • ์“ฐ๊ธฐ๊ฐ€ ๋” ์‰ฝ๋‚˜์š”?

      _๊ฐœ๋ฐœ์ž๋Š” ์ƒˆ๋กœ์šด ๊ฐœ๋…์˜ hook์„ ์ž‘์„ฑํ•˜๋Š” ๋ฒ•์„ ๋ฐฐ์›Œ์•ผ ํ•˜๋ฏ€๋กœ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค._ โŒ

  • ์ฝ”๋“œ๋Š” ์–ผ๋งˆ๋‚˜ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _StatefulWidget๋งŒํผ ์ •ํ™•ํžˆ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค๋ฅธ ์žฅ์†Œ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค._ โœ…
  • ์ด API๋กœ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
    _StatefulWidget์— ๋Œ€ํ•œ ๊ตฌ๋ฌธ ์„คํƒ•์ด๋ฏ€๋กœ ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค._ ๐Ÿ”ท
  • ์ผ๋ถ€ ํŠน์ • ๋ฌธ์ œ๋กœ ์ธํ•ด ์ผ๋ถ€ ํ˜œํƒ์„ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๊นŒ?
    _์„ฑ๋Šฅ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ €ํ•˜๋ฉ๋‹ˆ๋‹ค._ โŒ

์™œ ์šฐ๋ฆฌ๊ฐ€ ๊ณ„์† ์žฅํ™ฉํ•˜๊ฒŒ ๋Œ์•„๊ฐ€๋Š”์ง€ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ ๋ฌธ์ œ๋Š” ์žฌ์‚ฌ์šฉ์„ฑ ๋Œ€ ๊ฐ€๋…์„ฑ ๋Œ€ ์œ ์—ฐ์„ฑ์ด๋ผ๊ณ  ์—ฌ๋Ÿฌ ๋ฒˆ ๋ช…์‹œ์ ์œผ๋กœ ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์†์„ฑ์ด ๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๋‹ค๊ณ  ๋งํ•œ ์‚ฌ๋žŒ์ด ๋ˆ„๊ตฌ์ธ์ง€ ์ž˜๋ชป ๊ธฐ์–ตํ–ˆ์Šต๋‹ˆ๋‹ค. ๋„ค ๋ง์ด ๋งž์•„, ๋‹น์‹ ์˜ ์šฐ๋ ค๋Š” ์ด์ „์— ๋‚˜์—ด๋˜์ง€ ์•Š์€ ์ƒˆ๋กœ์šด ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์žˆ์–ด์„œ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ–ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ Property๋ฅผ ํ™•์žฅํ•˜์—ฌ ํ•ด๋‹น ์‚ฌ์šฉ ์‚ฌ๋ก€๋„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์‚ฌ์†Œํ•œ ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค(๋‚˜๋Š” ์‹œ๋„ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ์š”๊ตฌ ์‚ฌํ•ญ์ด ์กฐ์ •๋  ๋•Œ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฐ˜๋ณตํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋ฌธ์ œ๋ฅผ ํ•œ ๋ฒˆ์— ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ช…ํ™•ํ•œ ๋ฐ๋ชจ ์•ฑ์ด ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@szotp

  1. ์ด ๊ธฐ๋Šฅ IMO๋Š” ์˜ˆ๋ฅผ ๋“ค์–ด LayoutBuilder๋ฅผ ํฌํ•จํ•œ ๋ชจ๋“  ๋นŒ๋” ์œ„์ ฏ์œผ๋กœ ํ™•์žฅ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

LayoutBuilder๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๋นŒ๋”์ธ FWIW์™€๋Š” ๋งค์šฐ ๋‹ค๋ฅธ ์œ„์ ฏ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ๋…ผ์˜๋œ ์ œ์•ˆ ์ค‘ ์–ด๋Š ๊ฒƒ๋„ LayoutBuilder์™€ ์œ ์‚ฌํ•œ ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๊ท€ํ•˜์˜ ์˜๊ฒฌ ์ „์— ์„ค๋ช…๋œ ์š”๊ตฌ ์‚ฌํ•ญ์—๋Š” LayoutBuilder๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ LayoutBuilder๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š”์ง€๋„ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. @TimWhiting ๊ณผ

  1. ๋ฆฌ์Šค๋‹์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์•ผ 10x ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ๋ฆฌํ”„์— ์ „๋‹ฌํ•˜์—ฌ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๊ฑฐ๋‚˜ flutter๊ฐ€ ๋นŒ๋”์—์„œ ์–ป์€ ๊ฐ’์„ ํŠธ๋ฆฌ์˜ ์–ด๋Š ๋ถ€๋ถ„์—์„œ ์‚ฌ์šฉํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์ •ํ™•ํžˆ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋งํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ ์˜ค๋Š˜์€ ๋ฆฌ์Šค๋„ˆ์™€ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ์ •ํ™•ํžˆ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์•ž์„œ ์ธ์šฉํ•œ ์•ฑ์—์„œ ValueListenableBuilder๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค).

์ด๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋‚˜์—ดํ•œ ๊ฝค ํ•ฉ๋ฆฌ์ ์ธ ์ œ์•ฝ ์กฐ๊ฑด(์˜ˆ: @Rudiksz)์„ ์œ„๋ฐ˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋นŒ๋“œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋™์•ˆ ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ด๋ฏธ *Builders๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•”์‹œ์ ์œผ๋กœ ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ •ํ™•ํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋”์— ๋”ฐ๋ผ ๋‹ค๋ฅด์ง€๋งŒ ์ผ๋ถ€๋Š” initState, didChangeDependencies, didUpdateWidget ๋ฐ ๋นŒ๋“œ ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋งค์šฐ ์—ด์‹ฌํžˆ ์ผํ•˜๋ฏ€๋กœ ์ตœ์†Œํ•œ์˜ ์ฝ”๋“œ๋งŒ ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐ ๋นŒ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ValueListenableBuilder๋Š” ์ฒ˜์Œ ์ƒ์„ฑ๋  ๋•Œ๋งŒ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•˜๋ฉฐ, ํ•ด๋‹น ๋นŒ๋”๋Š” ์ƒ์œ„ ๋˜๋Š” ๋นŒ๋” ์žฌ์‹คํ–‰์˜ initState ์—†์ด ์žฌ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Hooks๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค.

@esDotDev ๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์€ ๋‚ด๊ฐ€ ์ด์ „์— Property๋กœ ์ œ์•ˆํ•œ ๊ฒƒ๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค( ์˜ˆ: #51752(comment) ์ฐธ์กฐ ).

๋‚ด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ•œ๋‹ค๋ฉด, UserId์— ๋Œ€ํ•œ DidDependancyChange ๋˜๋Š” AnimationProperty ๋˜๋Š” ํ•ด๋‹น ์œ ํ˜•์— ๋Œ€ํ•œ init/update/dispose๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋‹ค๋ฅธ ์†์„ฑ์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” UserProperty ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋Ÿฌ๋ฉด ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์ข‹์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋ฅผ ์‹ค๋ง์‹œํ‚ค๋Š” ์œ ์ผํ•œ ๊ฒƒ์€ ์—ฌ๊ธฐ ๋ฏธ๋ž˜์˜ ๊ฑด์ถ•๊ฐ€์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ๋‹จ์ง€ ๋‹น์‹ ์ด ์„ ํƒํ•œ ์˜ˆ ๋•Œ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ?

์˜ˆ๋ฅผ ๋“ค์–ด ์ด๊ฒƒ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

class _ExampleState extends State<Example> with PropertyManager {
  AnimationProperty animProp1;
  AnimationProperty animProp2;

  <strong i="15">@override</strong>
  void initProperties() {
    super.initProperties();
    anim1= register(anim1, AnimationProperty (
      AnimationController(duration: Duration(seconds: 1)),
      initState: (animator) => animator.forward()
      // Not dealing with updates or dispose here, cause AnimationProperty handles it
    ));
   anim2 = register(anim2, AnimationProperty(
       AnimationController(duration: Duration(seconds: 2))..forward(),
   ));
  }

  <strong i="16">@override</strong>
  Widget build(BuildContext context) {
    return Column(children: [
       FadeTransition(opacity: anim1, child: ...),
       FadeTransition(opacity: anim2, child: ...),
   ])
  }
}

๊ทธ๋ ‡๋‹ค๋ฉด ์ด๊ฒƒ์€ ์™„์ „ํžˆ LGTM์ž…๋‹ˆ๋‹ค! ํ”„๋ ˆ์ž„์›Œํฌ์— ์ถ”๊ฐ€ํ•œ๋‹ค๋Š” ์ ์—์„œ 1๊ธ‰ ๊ตฌ๋ฌธ ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ์Šน๊ฒฉ๋˜์–ด์•ผ ํ•˜๋Š”์ง€(1๋…„ ์ •๋„๋ฉด ์ผ๋ฐ˜ ๊ด€ํ–‰์ด ๋จ์„ ์˜๋ฏธํ•จ), ์•„๋‹ˆ๋ฉด ๊ฐœ๋ฐœ์ž์˜ ํ•œ ์ž๋ฆฌ ์ˆ˜ ๋น„์œจ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์กด์žฌํ•˜๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜๋‹ค.

์žฅํ™ฉํ•˜๊ณ  (์•ฝ๊ฐ„?) ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด ์˜ˆ์ œ๋ฅผ ๋” ๊ฐ„๊ฒฐํ•œ ๊ตฌ๋ฌธ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์˜ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ์†์„ฑ์„ ์ˆ˜๋™์œผ๋กœ ๋™๊ธฐํ™”ํ•˜๊ณ  ํ•ญ๋ชฉ์„ ์ˆ˜๋™์œผ๋กœ dispose()ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ๋ฒ„๊ทธ์™€ ์ธ์ง€ ๋ถ€ํ•˜๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ๋‘ ๋ฒˆ ์ƒ๊ฐํ•  ํ•„์š” ์—†์ด ์ ์ ˆํ•œ didUpdate ๋ฐ dispose ๋ฐ debugFillProperties ๋ฐ ์ „์ฒด ์ž‘๋™๊ณผ ํ•จ๊ป˜ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฐœ๋ฐœ์ž๋Š” Animator๋ฅผ ์ˆ˜๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์ด๊ฒƒ์€ ์™„์ „ํžˆ LGTM์ž…๋‹ˆ๋‹ค! ํ”„๋ ˆ์ž„์›Œํฌ์— ์ถ”๊ฐ€ํ•œ๋‹ค๋Š” ์ ์—์„œ 1๊ธ‰ ๊ตฌ๋ฌธ ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ์Šน๊ฒฉ๋˜์–ด์•ผ ํ•˜๋Š”์ง€(1๋…„ ์ •๋„๋ฉด ์ผ๋ฐ˜ ๊ด€ํ–‰์ด ๋จ์„ ์˜๋ฏธํ•จ), ์•„๋‹ˆ๋ฉด ๊ฐœ๋ฐœ์ž์˜ ํ•œ ์ž๋ฆฌ ์ˆ˜ ๋น„์œจ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์กด์žฌํ•˜๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜๋‹ค.

Property ๊ฐ€ ์–ผ๋งˆ๋‚˜ ์‚ฌ์†Œํ•œ์ง€ ๊ฐ์•ˆํ•  ๋•Œ, ๊ทธ ์Šคํƒ€์ผ์„ ์ข‹์•„ํ•˜๋Š” ์‚ฌ๋žŒ์—๊ฒŒ ์ถ”์ฒœํ•˜๋Š” ๊ฒƒ์€ ์ž์‹ ๋งŒ์˜ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค๊ณ (๋„์›€์ด๋œ๋‹ค๋ฉด ๋‚ด ์ฝ”๋“œ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ผ ์ˆ˜๋„ ์žˆ์Œ) ์ ์ ˆํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋Œ€๋กœ ์•ฑ์—์„œ ์ง์ ‘ ์‚ฌ์šฉํ•˜๊ณ  ์กฐ์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋“ค์˜ ํ•„์š”๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด. ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์ข‹์•„ํ•œ๋‹ค๋ฉด ํŒจํ‚ค์ง€๋กœ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์‚ฌ์†Œํ•œ ์ผ์— ๋Œ€ํ•ด์„œ๋Š” ์ฝ”๋“œ์— ๋ณต์‚ฌํ•˜๊ณ  ํ•„์š”์— ๋”ฐ๋ผ ์กฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ์œ ์ตํ•œ์ง€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋ฅผ ์‹ค๋ง์‹œํ‚ค๋Š” ์œ ์ผํ•œ ๊ฒƒ์€ ์—ฌ๊ธฐ ๋ฏธ๋ž˜์˜ ๊ฑด์ถ•๊ฐ€์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ๋‹จ์ง€ ๋‹น์‹ ์ด ์„ ํƒํ•œ ์˜ˆ ๋•Œ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ?

@rrousselGit์ด ์ œ๊ณตํ•œ ์˜ˆ์ œ๋ฅผ

์˜ˆ๋ฅผ ๋“ค์–ด ์ด๊ฒƒ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

AnimationController ์ƒ์„ฑ์ž๋ฅผ ๋งค๋ฒˆ ํ˜ธ์ถœํ•˜๋Š” ๋Œ€์‹  ํ˜ธ์ถœ๋˜๋Š” ํด๋กœ์ €๋กœ ์˜ฎ๊ธฐ๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด initProperties ๋Š” ์ƒˆ๋กœ์šด ํด๋กœ์ €๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ํ•ซ ๋ฆฌ๋กœ๋“œ ์ค‘์— ํ˜ธ์ถœ๋˜์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‹ถ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•ซ ๋ฆฌ๋กœ๋“œ ์ค‘ ์ƒˆ ์ปจํŠธ๋กค๋Ÿฌ(์˜ˆ: ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์žฌ์„ค์ •ํ•จ). ํ•˜์ง€๋งŒ ๋„ค, ๊ทธ ์™ธ์—๋Š” ๊ดœ์ฐฎ์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ํ•  ์ˆ˜์žˆ๋Š” AnimationControllerProperty ์†Œ์š” AnimationController ์ƒ์„ฑ์ž ์ธ์ž๋ฅผ ๊ทธ๋“ค๊ณผ ํ•จ๊ป˜ ์˜ฌ๋ฐ”๋ฅธ ์ผ์„ (๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๊ฒฝ์šฐ๋Š” ์˜ˆ๋ฅผ ๋“ค์–ด ๋œจ๊ฑฐ์šด ๋‹ค์‹œ๋กœ๋“œ์— ์‹œ๊ฐ„์„ ์—…๋ฐ์ดํŠธ).

๊ฐœ๋ฐœ์ž๊ฐ€ ๋‘ ๋ฒˆ ์ƒ๊ฐํ•  ํ•„์š” ์—†์ด ์ ์ ˆํ•œ didUpdate ๋ฐ dispose ๋ฐ debugFillProperties ๋ฐ ์ „์ฒด ์ž‘๋™๊ณผ ํ•จ๊ป˜ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฐœ๋ฐœ์ž๋Š” Animator๋ฅผ ์ˆ˜๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๋‚˜์˜ ๊ฑฑ์ •์€ ํ• ๋‹น ๋ฐ ํ๊ธฐ ์‹œ์ ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜์ง€ ์•Š์œผ๋ฉด ํ•ญ์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๋งŽ์€ ๊ฒƒ์„ ํ• ๋‹นํ•˜๊ฑฐ๋‚˜ ๊ทธ๋ ‡์ง€ ์•Š์€ ๋…ผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋” ๋†’๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹คํ–‰ํ•ด์•ผ ํ•˜๊ฑฐ๋‚˜ ๋œ ํšจ์œจ์ ์ธ ์ฝ”๋“œ๋กœ ์ด์–ด์ง€๋Š” ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ์ด๊ฒƒ์„ ๊ธฐ๋ณธ ๊ถŒ์žฅ ์Šคํƒ€์ผ๋กœ ๋งŒ๋“ค๊ธฐ๋ฅผ ๊บผ๋ฆฌ๋Š” ์ด์œ  ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

AnimationController ์ƒ์„ฑ์ž ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ฌ๋ฐ”๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” AnimationControllerProperty๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ ํ•ซ ๋ฆฌ๋กœ๋“œ ์‹œ ์ง€์† ์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ).

@Hixie ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ •๋ง ๋ฉ‹์ง€๊ณ  ๋ฌธ์ œ๋ฅผ ์ž˜ ํ•ด๊ฒฐํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ์ด๋Ÿฌํ•œ ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ 99% ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ ์‚ฌ์šฉ๋˜๋Š” StatefulWidget์— ๋ฐ”์ธ๋”ฉ๋˜์–ด ์žˆ๊ณ  ๊ทธ ์ด์™ธ์˜ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ด๋ฏธ ์ค‘๊ฐ„ ๊ฐœ๋ฐœ์ž ์˜์—ญ์œผ๋กœ ์ด๋™ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ์ด๊ฒƒ์ด ์›์‹œ AnimatorController๋ณด๋‹ค TweenAnimationBuilder๋ฅผ ๊ถŒ์žฅํ•˜๋Š” ๊ฒƒ๊ณผ ๊ทผ๋ณธ์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ์ด ๋‹ค๋ฅธ ์ƒํƒœ์—์„œ ๊ด€๋ฆฌ ์ƒํƒœ ์ง€๋ถ„์„ ํฌํ•จ์„ / ์›ํ•˜๋Š” (๊ทธ๋ฆฌ๊ณ  ๋‹น์‹ ์ด ์›ํ•˜๋Š” ๋ณดํ†ต) ๊ฒฝ์šฐ, ๋‹ค์Œ์ด ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ƒ๊ฐ์ด๋‹ค.

์ด ์‹œ์ ์—์„œ ์šฐ๋ฆฌ๋Š” ํ†ตํ™”๋ฅผ ์กฐ์งํ•˜๊ณ  ๋‹ค์–‘ํ•œ ์ดํ•ด ๊ด€๊ณ„์ž์™€ ํ•จ๊ป˜ ๋…ผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๊ฐ™์€ ์งˆ๋ฌธ์— ๊ณ„์†ํ•ด์„œ ๋‹ตํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ํ† ๋ก ์ด ์ง„ํ–‰๋˜์ง€ ์•Š๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๋ ‡๊ฒŒ ๊ธด ํ† ๋ก ๊ณผ ๋งŽ์€ ๋…ผ์Ÿ ๋์— ์–ด๋–ป๊ฒŒ StatefulWidget์— ๋น„ํ•ด ๋นŒ๋”๊ฐ€ ์‹ค์ˆ˜๋ฅผ ํ”ผํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ํ›„ํฌ๊ฐ€ ์›์‹œ StatefulWidget๋ณด๋‹ค ๋” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ฃผ์žฅํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ์ฃผ์š” ์„ ์–ธ์  ํ”„๋ ˆ์ž„์›Œํฌ(React, Vue, Swift UI, Jetpack Compose)์— ์ด ๋ฌธ์ œ๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•˜๋ฉด ํŠนํžˆ ์‹ค๋ง์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.
Flutter๋งŒ์ด ์ด ๋ฌธ์ œ๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@esDotDev IMHO๊ฐ€ AnimationBuilder, TweenAnimationBuilder ๋˜๋Š” ValueListenableBuilder๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฃผ๋œ ์ด์œ ๋Š” ํ˜ธ์ŠคํŠธ ์œ„์ ฏ์˜ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์„ ๋‹ค์‹œ ๋นŒ๋“œํ•˜์ง€ ์•Š๊ณ  ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์„ฑ๋Šฅ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์ •๋ณด๋‚˜ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‚ด ๋ง์€, ๊ทธ๋Ÿฌํ•œ ์ด์œ ๋กœ ๊ทธ๊ฒƒ๋“ค์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌํ•œ ์ด์œ ๋กœ ์œ ์šฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋ฉด ์ ์–ด๋„ ์ €์—๊ฒŒ๋Š” ๊ทธ๊ฒƒ์ด ์ฃผ์š” ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋˜ํ•œ Property(๋˜๋Š” Hooks)๊ฐ€ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฌด์–ธ๊ฐ€๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ _entire_ ์œ„์ ฏ์„ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๊ฒŒ ๋˜๋ฉฐ, ์ด๋Š” ์„ฑ๋Šฅ์— ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@rrousselGit

Flutter๋งŒ์ด ์ด ๋ฌธ์ œ๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ €๋Š” ์ด๋ฒˆ ์ฃผ๋ง์— ๋ฌธ์ž ๊ทธ๋Œ€๋กœ ๋ช‡ ์‹œ๊ฐ„์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ „์—๋Š” Google์—์„œ ๋ณด๋‚ธ ๋งŽ์€ ์‹œ๊ฐ„์€ ๋งํ•  ๊ฒƒ๋„ ์—†๊ณ , ์ด ๋ฌธ์ œ๋ฅผ ๊ณ ๋ คํ•˜๊ณ  ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์„ ์„ค๋ช…ํ•˜๊ณ  ์šฐ๋ฆฌ๊ฐ€ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๊ฒƒ์„ ์ •ํ™•ํ•˜๊ฒŒ ๋„์ถœํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค. ์ดํ•ด์˜ ๋ถ€์กฑ๊ณผ ๊ณ ๋ ค๋ฅผ ๊ฑฐ๋ถ€ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ˜ผ๋™ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ํŠนํžˆ ์ด ๋ฌธ์ œ๋ฅผ ๊ณ„์† ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ์„ ์˜ ๋ฐฉ๋ฒ•์„ ์ด๋ฏธ ์„ค๋ช…ํ•œ ๊ฒฝ์šฐ(๋ฌธ์ œ ์ œ๋ชฉ์„ ์ธ์šฉํ•˜๊ฑฐ๋‚˜ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” "๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๊ฑฐ๋‚˜ ๋„ˆ๋ฌด ์–ด๋ ค์šด" ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ๋ชจ๋‘ ํฌํ•จํ•˜๋Š” ๋ฐ๋ชจ ์•ฑ ๋งŒ๋“ค๊ธฐ) ์ด ๋ฒ„๊ทธ์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์ž‘์—…์„ ๋งก์•˜๊ณ  ๊ท€ํ•˜๊ฐ€ ์ฐธ์—ฌ๋ฅผ ๊ฑฐ๋ถ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

The main reason IMHO to use an AnimationBuilder or TweenAnimationBuilder or ValueListenableBuilder is that they rebuild only when the value changes, without rebuilding the rest of their host widget. It's a performance thing.

ํฅ๋ฏธ๋กœ์šด. ์šฐ๋ฆฌ๋Š” ์‹ค์ œ๋กœ ์ด์™€ ๊ฐ™์€ ์†Œ๊ทœ๋ชจ ์žฌ๊ตฌ์ถ•์„ ์ €์žฅํ•จ์œผ๋กœ์จ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์ธก์ •ํ•˜๊ฑฐ๋‚˜ ๊ด€์ฐฐํ•œ ์ ์ด ์—†์Šต๋‹ˆ๋‹ค. 2์ฃผ๋งˆ๋‹ค ์ˆ˜๋ฐฑ ๊ฐœ์˜ ํด๋ž˜์Šค ํŒŒ์ผ์„ ์ œ๊ฑฐํ•  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ƒ์ ์ธ ์˜ค๋ฅ˜ ์—†์ด ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ณ  ๊ฐ€๋…์„ฑ ์žˆ๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๋Œ€๊ทœ๋ชจ ์•ฑ ์ฝ”๋“œ ๊ธฐ๋ฐ˜๋ณด๋‹ค ํ›จ์”ฌ ๋” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

RepaintBoundaries๋ฅผ ์˜๋„์ ์œผ๋กœ ์ •์˜ํ•˜์ง€ ์•Š๋Š” ํ•œ ์ „์ฒด ํŠธ๋ฆฌ์— ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š” ํ”ฝ์…€ ๋‹ค์‹œ ๊ทธ๋ฆฌ๊ธฐ ๋น„์šฉ์€ ๋ถ€๋ถ„ ์œ„์ ฏ ๋ ˆ์ด์•„์›ƒ ๋น„์šฉ๋ณด๋‹ค ์‹ค์ œ ์„ฑ๋Šฅ์—์„œ ํ›จ์”ฌ ๋” ์ค‘์š”ํ•œ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ 4k ๋ชจ๋‹ˆํ„ฐ ๋ฒ”์œ„์— ๋“ค์–ด๊ฐˆ ๋•Œ.

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ๊ฑด์ถ•์—…์ž๊ฐ€ ์‹ค์ œ๋กœ ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ์ผ์„ ์ดํ•ดํ•˜๋Š” ์ข‹์€ ์˜ˆ์ž…๋‹ˆ๋‹ค. ํ•˜์œ„ ์ปจํ…์ŠคํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด ๋นŒ๋”๊ฐ€ ์˜๋ฏธ๊ฐ€ ์žˆ์œผ๋ฉฐ ๊ฑฐ๊ธฐ์— ๋„๋‹ฌํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ Builder๋Š” ํด๋Ÿฌํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•  ๋ฟ์ด์ง€๋งŒ ๋Œ€์•ˆ์€ ๋‹ค๋ฅธ ์œ ํ˜•์˜ ํด๋Ÿฌํ„ฐ์ผ ๋ฟ์ด๋ฏ€๋กœ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ ์–ด๋„ Builder์—์„œ๋Š” ๋ฒ„๊ทธ๊ฐ€ ๊ฑฐ์˜ ์—†์Œ์ด ๋ณด์žฅ๋ฉ๋‹ˆ๋‹ค. ์ „์ฒด ๋ณด๊ธฐ๊ฐ€ ๋‹ค์‹œ ๋นŒ๋“œ๋˜๊ฑฐ๋‚˜ ๋ฐ˜๋“œ์‹œ ๋ณด๊ธฐ๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•  ํ•„์š”๊ฐ€ ์ „ํ˜€ ์—†๋Š” ๊ฒฝ์šฐ(TextEditingController, FocusController) ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ฑฐ์˜ ์˜๋ฏธ๊ฐ€ ์—†์œผ๋ฉฐ ๋ชจ๋“  ๊ฒฝ์šฐ์— ์ƒ์šฉ๊ตฌ๋ฅผ ์†์œผ๋กœ ๊ตด๋ฆฌ๋Š” ๊ฒƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ DRY๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ํ™•์‹คํžˆ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ๊ทธ๋Ÿฐ ์Šคํƒ€์ผ์„ ์ข‹์•„ํ•œ๋‹ค๋ฉด Hooks๋‚˜ Property ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์˜ค๋Š˜๋‚  ๊ฐ€๋Šฅํ•˜๋ฉฐ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•œ ๊ฒƒ์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  Property์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ์‹ค์ œ๋กœ ๋งŽ์€ ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค).

์•„๋‹ˆ์š”, ํ•˜์ง€๋งŒ ์ปค๋ฎค๋‹ˆํ‹ฐ์— TweenAnimationBuilder ๋ฐ ValueListenableBuilder๋ฅผ ๋นŒ๋“œํ•˜๋„๋ก ์š”์ฒญํ•˜๊ณ  ๋นŒ๋“œํ•  StatefulWidget์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋‹น์‹ ์ด ๋ฌป๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ์•„ํ‚คํ…์ฒ˜์˜ ์ฃผ์š” ์ด์  ์ค‘ ํ•˜๋‚˜๋Š” ์‰ฝ๊ฒŒ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ์•„์ฃผ ์ž‘์€ ๊ตฌ์„ฑ ์š”์†Œ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ ํ•ฉํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ž‘์€ ๊ธฐ์ดˆ ์กฐ๊ฐ์„ ์ œ์ž๋ฆฌ์— ๋ฐฐ์น˜ํ•˜๋ฉด ...

StatefulWidget์€ Property์— ๋น„ํ•ด _lot_ ๋งŽ์€ ์ฝ”๋“œ์ด๋ฉฐ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋Œ€๋ถ€๋ถ„ ๊ธ€๋ฃจ ์ฝ”๋“œ์ธ Property์™€ ๋‹ฌ๋ฆฌ). ์ฆ‰, Property๊ฐ€ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋ผ๋ฉด(์ •ํ™•ํ•œ ํ•„์š”์— ๋”ฐ๋ผ ๊ฐ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด๋‚˜ ํŒ€์— ๋Œ€ํ•œ ๋งž์ถคํ˜• ๋ฒ„์ „์„ ๋งŒ๋“œ๋Š” ๊ฒƒ๊ณผ๋Š” ๋Œ€์กฐ์ ์œผ๋กœ), ๋‚˜๋Š” ๊ทธ ์‚ฌ์šฉ์„ ์˜นํ˜ธํ•˜๋Š” ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค์–ด ์—…๋กœ๋“œํ•˜๋„๋ก ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. pub . ์‹ค์ œ๋กœ Hooks์—๋„ ๋™์ผํ•˜๊ฒŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ์ข‹์•„ํ•˜๋Š” ๊ฒƒ์ด๋ผ๋ฉด Provider์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ ์ž์ฒด์— ๊ทธ๋Ÿฐ ๊ฒƒ์„ ๋„ฃ์–ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋ณธ์งˆ์ ์œผ๋กœ ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ณต๊ธ‰์ž๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ๋‹จ์ˆœํ•œ ๋„๊ตฌ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ StatefulWidget๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ StatefulComponent๋ฅผ ์œ„ํ•ด ํ™•์žฅ๋˜๋„๋ก ๋งŒ๋“ค์–ด์ง„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ƒ๋Œ€์ ์œผ๋กœ ์‚ฌ์†Œํ•˜๋‹ค๋Š” ์‚ฌ์‹ค์ด ๋ฐ˜๋“œ์‹œ ๋ฐ˜๋Œ€๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒƒ ์•„๋‹Œ๊ฐ€?

"์ด ์Šคํƒ€์ผ์„ ์„ ํ˜ธํ•˜๋Š” ์‚ฌ๋žŒ๋“ค"์— ๋Œ€ํ•œ ๋ฉ”๋ชจ. 3๊ฐœ์˜ ์žฌ์ •์˜์™€ 15-30์ค„์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ๊ด€์ ์œผ๋กœ ๋งํ•˜์ž๋ฉด. ๋˜ํ•œ ๊ฐ๊ด€์ ์œผ๋กœ 2๊ฐ€์ง€ ์ „์ฒด ์˜ค๋ฅ˜ ํด๋ž˜์Šค๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค(์‚ฌ๋ฌผ ์ฒ˜๋ฆฌ๋ฅผ ์žŠ๊ฑฐ๋‚˜ deps ์—…๋ฐ์ดํŠธ๋ฅผ ์žŠ์Œ).

๋ฉ‹์ง„ ํ† ๋ก ์— ๋Œ€ํ•ด ์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์–ด๋””๋กœ ๊ฐ€๋Š”์ง€ ๋ณด๊ณ  ํฅ๋ถ„๋ฉ๋‹ˆ๋‹ค. ์ €๋Š” ํ™•์‹คํžˆ ์—ฌ๊ธฐ์— ๋‚จ๊ธธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. :)

์ด ์Šค๋ ˆ๋“œ๊ฐ€ ๋‚ด๊ฐ€ ์ž‘์—… ์ค‘์ธ ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งˆ์น  ๋•Œ ๊ณ„ํšํ–ˆ๋˜ ํ”Œ๋Ÿฌํ„ฐ์— ๋‹ค์‹œ ๋น ์ ธ๋“œ๋Š” ๊ฒƒ์„ ํ™˜๋ฉธ์Šค๋Ÿฝ๊ฒŒ ๋งŒ๋“ ๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์„ ์œ ๊ฐ์Šค๋Ÿฝ๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋•Œ๋ฌธ์— ์ขŒ์ ˆ๋„ ๋Š๋‚€๋‹ค.

๋ชจ๋“  ์ฃผ์š” ์„ ์–ธ์  ํ”„๋ ˆ์ž„์›Œํฌ(React, Vue, Swift UI, Jetpack Compose)์— ์ด ๋ฌธ์ œ๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•˜๋ฉด ํŠนํžˆ ์‹ค๋ง์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐ˜๋ณตํ•ด์„œ ๋ช…ํ™•ํ•˜๊ฒŒ ์„ค๋ช…๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— Flutter ์˜ˆ์ œ ์•ฑ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์„ ํ• ์• ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋Š” ์ ์—์„œ
๋˜ํ•œ ์•ฑ์„ ์ž‘์„ฑํ•˜๋ ค๋ฉด ์†”๋ฃจ์…˜์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์†”๋ฃจ์…˜์„ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด ํ”Œ๋Ÿฌํ„ฐ๋กœ ์•ฑ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋Œ€ํ™”์˜ ํ”Œ๋Ÿฌํ„ฐ ์‚ฌ๋žŒ๋“ค์€ ์ตœ์†Œํ•œ ํ›„ํฌ๋ฅผ ์ข‹์•„ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด ๊ฝค ๋ถ„๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Flutter์—๋Š” OP์— ์„ค๋ช…๋œ ๋Œ€๋กœ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์ด ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ์ž‘์„ฑํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

(์ ์–ด๋„ ๋‚˜์—๊ฒŒ๋Š”) ์ด๊ฒƒ์ด ์‹ฌ๊ฐํ•˜๊ฒŒ ๋ฐ›์•„๋“ค์—ฌ์ง€์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. @Hixie ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. We understand the problem and want to solve it ์˜๋ฏธ์—์„œ ์‹ฌ๊ฐํ•˜๊ฒŒ ๋ฐ›์•„๋“ค์ด์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์„ ์–ธ์  ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ถ„๋ช…ํžˆ ์™„๋ฃŒ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
๋˜ ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ๋™์ผํ•œ ๋ฉ”๋ชจ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‚ด์šฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์“ฐ๊ธฐ๊ฐ€ ๋” ์‰ฝ๋‚˜์š”?
๊ฐœ๋ฐœ์ž๋Š” ์ƒˆ๋กœ์šด ๊ฐœ๋…์ธ ํ›„ํฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฒ•์„ ๋ฐฐ์›Œ์•ผ ํ•˜๋ฏ€๋กœ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋‚˜๋ฅผ ์Šฌํ”„๊ฒŒ ๋งŒ๋“ค์–ด. ์™œ ๊ฐœ์„ ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๊นŒ? ๋‹น์‹ ์€ ๋ฌด์Šจ ์ผ์ด ์žˆ์–ด๋„ ํ•ญ์ƒ ๊ทธ ์ฃผ์žฅ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ์†”๋ฃจ์…˜์ด ํ•œ ๋ฒˆ ๋ฐฐ์šฐ๋ฉด ํ›จ์”ฌ ์‰ฝ๊ณ  ์ฆ๊ฒ๋”๋ผ๋„. ํ•ด๋‹น ๋ช…๋ น๋ฌธ์˜ ํ›„ํฌ๋ฅผ ๋งŽ์€ ๊ฒƒ์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ์—„๋งˆ๋Š” 30๋…„ ์ „์— ์ „์ž๋ ˆ์ธ์ง€์— ๋Œ€ํ•ด ๊ทธ๋Ÿฐ ๋ง์„ ์‚ฌ์šฉํ–ˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฌธ์žฅ์—์„œ "hooks"๋ฅผ "flutter" ๋˜๋Š” "dart"๋กœ ๋ฐ”๊พธ๋ฉด ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์“ฐ๊ธฐ๊ฐ€ ๋” ์‰ฝ๋‚˜์š”?
๋˜‘๊ฐ™์œผ๋‹ˆ ์“ฐ๊ธฐ๋„ ์‰ฝ๋„ค์š”.

is it easier to write? (๋ถ€์šธ ๋‹ต๋ณ€ ์งˆ๋ฌธ)์—์„œ @rrousselGit์ด ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋Š” ๋™์ผํ•˜๋‹ค๋ฉด ๋Œ€๋‹ต์ด false / undefined ๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์— ๋™์˜ํ•˜์ง€๋„ ์•Š๊ณ  ๋‹จ์ง€ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์ด๊ฒƒ์„ ๋ฌธ์ œ๋กœ ์—ฌ๊ธด๋‹ค๋Š” ์‚ฌ์‹ค์— ๋™์˜ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ป๊ฒŒ ์šฐ๋ฆฌ๊ฐ€ ์–ด๋”˜๊ฐ€์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ์„์ง€ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ:

๊ทธ๊ฒƒ์€ ํ™•์‹คํžˆ ์‚ฌ๋žŒ๋“ค์ด ์ œ๊ธฐํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‚ด๊ฐ€ ๋ณธ๋Šฅ์ ์œผ๋กœ ๊ฒฝํ—˜ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. Flutter๋กœ ๋‚ด ์ž์‹ ์˜ ์•ฑ์„ ์ž‘์„ฑํ•  ๋•Œ ๋ฌธ์ œ๋ผ๊ณ  ๋Š๋‚€ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด์„œ ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์‹ค์ œ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์˜๋ฏธ๋Š” ์•„๋‹™๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด OP์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด ํ•ต์‹ฌ์— ์žˆ์–ด์•ผ ํ•˜๋Š” ์ด์œ ์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ๋ฒˆ ๋งŽ์€ ์ฃผ์žฅ์„ ํ–ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ .
์˜ˆ๋ฅผ ๋“ค์–ด, ์ œ3์ž๊ฐ€ ์˜ค๋Š˜๋‚  ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๊ณ  ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์‰ฝ๊ณ  ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋ฉด ํ•ต์‹ฌ์ด ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ ์ด์œ . ๋งŒํŠธ๋ผ๋Š” ํŒจํ‚ค์ง€์— ๋„ฃ๋Š” ๊ฒƒ๋ฟ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋ฏธ ํ›„ํฌ์™€ ๊ฐ™์€ ํŒจํ‚ค์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ํ•ด๊ฒฐ ๋œ ๊ฒƒ์ด๋ผ๋ฉด ์Šค๋ ˆ๋“œ๋ฅผ ๋‹ซ์œผ์‹ญ์‹œ์˜ค.

@rrousselGit์˜ ์ œ์•ˆ์„ ์ฃผ์„  ํ•ด

์–ด์จŒ๋“ , ๋‚˜๋Š” ์ด ์Šค๋ ˆ๋“œ๊ฐ€ ์–ด๋””๋กœ ๊ฐ€๋Š”์ง€ ๋ณด์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด ์Šค๋ ˆ๋“œ๋ฅผ ๋ผ์ด๋ธŒ ํŒ”๋กœ์šฐํ•˜๋Š” ๊ฒƒ์ด ์กฐ๊ธˆ ์Šฌํ”„๊ธฐ ๋•Œ๋ฌธ์— ์ง€๊ธˆ ๊ตฌ๋…์„ ์ทจ์†Œํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜๋Š” ์ƒํƒœ์— ๋„๋‹ฌํ•˜์—ฌ OP์— ๋Œ€ํ•œ ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. @Hixie๊ฐ€ ์•„๋งˆ๋„ ๋™์˜

์‚ฌ๋žŒ๋“ค์ด ์›ํ•˜์ง€๋งŒ ํ”Œ๋Ÿฌํ„ฐ๊ฐ€ ์ด ๋ฌธ์ œ๋ฅผ ํ•ต์‹ฌ์ ์œผ๋กœ ํ•ด๊ฒฐํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ๋‹จํ˜ธํ•˜๊ฒŒ ๋งํ•จ์œผ๋กœ์จ ์ด ์Šค๋ ˆ๋“œ๋ฅผ ๋๋‚ด๋Š” ๋ฐ ํ–‰์šด์ด ์žˆ๊ธฐ๋ฅผ ์ง„์‹ฌ์œผ๋กœ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋˜๋Š” ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๐Ÿ˜˜

LayoutBuilder๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๋นŒ๋”์ธ FWIW์™€๋Š” ๋งค์šฐ ๋‹ค๋ฅธ ์œ„์ ฏ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ๋…ผ์˜๋œ ์ œ์•ˆ ์ค‘ ์–ด๋Š ๊ฒƒ๋„ LayoutBuilder์™€ ์œ ์‚ฌํ•œ ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๊ท€ํ•˜์˜ ์˜๊ฒฌ ์ „์— ์„ค๋ช…๋œ ์š”๊ตฌ ์‚ฌํ•ญ์—๋Š” LayoutBuilder๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ LayoutBuilder๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š”์ง€๋„ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. @TimWhiting ๊ณผ

@Hixie ์˜ˆ, ํ™•์‹คํžˆ ์ƒ˜ํ”Œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋ญ”๊ฐ€๋ฅผ ์ค€๋น„ํ•  ๊ฒƒ์ด๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ์—ฌ์ „ํžˆ ์ปดํŒŒ์ผ๋Ÿฌ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜๋ฏ€๋กœ ์ƒ˜ํ”Œ์ด ๋ถˆ์™„์ „ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค). ์ผ๋ฐ˜์ ์ธ ์•„์ด๋””์–ด๋Š” - ๋นŒ๋”๋ฅผ ํ‰๋ฉดํ™”ํ•˜๊ณ  ๋นŒ๋”๊ฐ€ ๊ตฌํ˜„๋˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋Š” ๊ตฌ๋ฌธ ์„คํƒ•์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜๋„ Flutter ํŒ€์˜ ์–ด๋Š ๋ˆ„๊ตฌ๋„ SwiftUI๋ฅผ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ง€ ์•Š์•˜๋‹ค๋Š” ์ธ์ƒ์„ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์šฐ๋ฆฌ์˜ ์šฐ๋ ค๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šธ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋ฏธ๋ž˜๋ฅผ ์œ„ํ•ด์„œ๋Š” ๋‹ค๋ฅธ ํ”Œ๋žซํผ์—์„œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์ตœ๋Œ€ํ•œ ์›ํ™œํ•˜๊ฒŒ ํƒ€๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋ฏ€๋กœ ๋‹ค๋ฅธ ํ”Œ๋žซํผ์— ๋Œ€ํ•œ ์ถฉ๋ถ„ํ•œ ์ดํ•ด์™€ ์žฅ๋‹จ์ ์— ๋Œ€ํ•œ ์ง€์‹์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. Flutter์˜ ๋‹จ์  ์ค‘ ์ผ๋ถ€๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ Flutter๋Š” React์—์„œ ๋งŽ์€ ์ข‹์€ ์•„์ด๋””์–ด๋ฅผ ์–ป์—ˆ๊ณ  ์ €๋„ ์ƒˆ๋กœ์šด ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ๋˜‘๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@emanuel-lundman

(์ ์–ด๋„ ๋‚˜์—๊ฒŒ๋Š”) ์ด๊ฒƒ์ด ์‹ฌ๊ฐํ•˜๊ฒŒ ๋ฐ›์•„๋“ค์—ฌ์ง€์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. @Hixie ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. We understand the problem and want to solve it ์˜๋ฏธ์—์„œ ์‹ฌ๊ฐํ•˜๊ฒŒ ๋ฐ›์•„๋“ค์ด์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์„ ์–ธ์  ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ถ„๋ช…ํžˆ ์™„๋ฃŒ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๋ฐ ์ „์ ์œผ๋กœ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋‚ด๊ฐ€ ์ด ๋ฌธ์ œ์— ๊ณ„์† ๊ด€์—ฌํ•˜๊ณ  ์ดํ•ดํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ œ๊ฐ€ ๋ฌธ์ œ๋ฅผ ์บก์Šํ™”ํ•˜๋Š” ๋ฐ๋ชจ ์•ฑ์„ ๋งŒ๋“ค ๊ฒƒ์„ ์ œ์•ˆํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ์šฐ๋ฆฌ๊ฐ€ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๊ทผ๋ณธ์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์ˆ˜์ •ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•œ ๋ฌธ์ œ์ธ์ง€, ํ”„๋ ˆ์ž„์›Œํฌ์— ์ž‘์€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜, ํŒจํ‚ค์ง€๋กœ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜, ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”์ง€ ์—ฌ๋ถ€๋Š” ์‹ค์ œ๋กœ ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

@szotp

๊ทธ๋ž˜๋„ Flutter ํŒ€์˜ ์–ด๋Š ๋ˆ„๊ตฌ๋„ SwiftUI๋ฅผ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ง€ ์•Š์•˜๋‹ค๋Š” ์ธ์ƒ์„ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์šฐ๋ฆฌ์˜ ์šฐ๋ ค๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šธ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ €๋Š” ์Šค์œ„ํ”„ํŠธ UI๋ฅผ ๊ณต๋ถ€ํ–ˆ์Šต๋‹ˆ๋‹ค. Flutter ์ฝ”๋“œ๋ณด๋‹ค Swift UI ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ํ™•์‹คํžˆ ๋œ ์žฅํ™ฉํ•˜์ง€๋งŒ ๊ฐ€๋…์„ฑ ๋น„์šฉ์€ IMHO๊ฐ€ ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. "๋งˆ๋ฒ•"(์†Œ๋น„์ž ์ฝ”๋“œ์—์„œ ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ๋…ผ๋ฆฌ๋ผ๋Š” ์˜๋ฏธ์—์„œ)์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์ด ์„ ํ˜ธํ•˜๋Š” ์Šคํƒ€์ผ์ด๋ผ๊ณ  ์ „์ ์œผ๋กœ ๋ฏฟ์„ ์ˆ˜ ์žˆ์ง€๋งŒ Flutter์˜ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋Š” ๋งˆ์ˆ ์ด ๊ฑฐ์˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋•Œ๋•Œ๋กœ ๋” ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€๋งŒ, ๋˜ํ•œ ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๋Š” ๊ฒƒ์ด _ํ›จ์”ฌ_ ๋” ์‰ฝ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋งŽ์€ ์Šคํƒ€์ผ์˜ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์œ„ํ•œ ์—ฌ์ง€๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. MVC ์Šคํƒ€์ผ, React ์Šคํƒ€์ผ, ๋งค์šฐ ๊ฐ„๊ฒฐํ•œ ๋งˆ์ˆ , ๋งˆ์ˆ ์ด ํ•„์š” ์—†์ง€๋งŒ ์žฅํ™ฉํ•œ... Flutter ์•„ํ‚คํ…์ฒ˜์˜ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋Š” ์ด์‹์„ฑ ์ธก๋ฉด์ด ํ”„๋ ˆ์ž„์›Œํฌ ์ž์ฒด์™€ ์™„์ „ํžˆ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ๋ชจ๋“  ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. -- ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์ง€์›, ํ•ซ ๋ฆฌ๋กœ๋“œ ๋“ฑ -- ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. (์˜ˆ: flutter_sprites์™€ ๊ฐ™์€ ๋‹ค๋ฅธ Flutter ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ด๋ฏธ ์žˆ์Šต๋‹ˆ๋‹ค.) ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ”„๋ ˆ์ž„์›Œํฌ ์ž์ฒด๋„ ๋ ˆ์ด์–ด ๋ฐฉ์‹์œผ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ์–ด ์˜ˆ๋ฅผ ๋“ค์–ด ๋ชจ๋“  RenderObject ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์œ„์ ฏ ๋ ˆ์ด์–ด๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์ ฏ์ด ๋„ˆ๋ฌด ๋งŽ์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ์ด๋ฅผ ๋Œ€์ฒดํ•  ๋Œ€์ฒด ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ํŒจํ‚ค์ง• ์‹œ์Šคํ…œ์ด ์žˆ์œผ๋ฏ€๋กœ ๊ธฐ์กด ํ”„๋ ˆ์ž„์›Œํฌ ์ฝ”๋“œ๋ฅผ ์žƒ์ง€ ์•Š๊ณ  ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌํ•˜ํŠผ, ์—ฌ๊ธฐ์—์„œ ๋‚ด ์†Œ์‹ฌ์˜ ์š”์ ์€ ์ด๊ฒƒ์ด ์ „๋ถ€ ์•„๋‹ˆ๋ฉด ์ „๋ฌด๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์žฅ๊ธฐ์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ๋‹น์‹ ์„ ํ–‰๋ณตํ•˜๊ฒŒ ํ•˜๋Š” ์†”๋ฃจ์…˜์„ ์ฑ„ํƒํ•˜์ง€ ์•Š๋”๋ผ๋„, ๊ทธ๊ฒƒ์ด ๋‹น์‹ ์ด ์ข‹์•„ํ•˜๋Š” ์ œํ’ˆ์˜ ์ผ๋ถ€๋กœ๋ถ€ํ„ฐ ๊ณ„์† ํ˜œํƒ์„ ๋ฐ›์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.


์ด ๋ฌธ์ œ์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์€ @TimWhiting ๊ณผ ๋ถˆ๊ฐ€๋Šฅํ•  ๋•Œ ์˜ค๋Š˜๋‚ ์˜ ๋ชจ์Šต์„ ๋ณด์—ฌ์ฃผ๋Š” ์•ฑ์„ ๋งŒ๋“ค ๊ฒƒ์„ ์ด‰๊ตฌํ•ฉ๋‹ˆ๋‹ค(https://github.com/TimWhiting/local_widget_state_approaches). ์ด๊ฒƒ์€ ์—ฌ๊ธฐ์— ๋Œ“๊ธ€์„ ๋‹ฌ๊ณ  ์žˆ๋Š” _๋ชจ๋“ __ ์‚ฌ๋žŒ๋“ค(Hooks๋ฅผ ์ข‹์•„ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค๊ณผ Hooks๋ฅผ ์ข‹์•„ํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ๋“ค ํฌํ•จ)์˜ ์š”๊ตฌ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ œ์•ˆ์„ ๋งŒ๋“œ๋Š” ๋ฐ ์ง์ ‘์ ์ธ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

"_๋นŒ๋”๋ฅผ ํ‰๋ฉดํ™”ํ•˜๊ณ  ๋นŒ๋”๊ฐ€ ๊ตฌํ˜„๋˜๋Š” ๋ฐฉ๋ฒ•์— ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋Š” ๊ตฌ๋ฌธ ์„คํƒ•._"์ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ผ๊ธ‰ ๊ธฐ๋Šฅ์œผ๋กœ ์›ํ•˜๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ์ •๋ง ์–ด๋ ต์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋Œ€์ฒด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋ฌธ์ œ๋ฅผ ๊ณ„์†ํ•ด์„œ ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ ๋นŒ๋”๋Š” ์žฌ์‚ฌ์šฉ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€๋งŒ ์ฝ๊ณ  ์ž‘์„ฑํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. "๋ฌธ์ œ"๋Š” ๋‹จ์ˆœํžˆ ์šฐ๋ฆฌ๊ฐ€ ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฌ์šด ๋นŒ๋”์™€ ์œ ์‚ฌํ•œ ๊ธฐ๋Šฅ์„ ์›ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

3๊ฐœ์˜ ์ค‘์ฒฉ๋œ ๋นŒ๋”๊ฐ€ ์ฝ๊ธฐ ์–ด๋ ต๊ฑฐ๋‚˜ ์ผ๋ฐ˜์ ์œผ๋กœ ๋นŒ๋”๊ฐ€ ์‹ค์ œ๋กœ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ชฉ์ ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ฐ ๊ทผ๋ณธ์ ์œผ๋กœ ๋™์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์•ฑ์ด ์ด๋ฅผ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ๋ณด์—ฌ์ค„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ์ค‘ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์‹ค์ œ๋กœ ์ค‘์ฒฉ์„ ์ค„์ด๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์— ์ฝ”๋“œ๋ฅผ ๋ณต์ œํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋“ฃ๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” 2๊ฐ€์ง€ ๋น„์ด์ƒ์ ์ธ ์˜ต์…˜ ์‚ฌ์ด์— ๊ฐ‡ํ˜€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ๊ณ ๋ คํ•˜๊ณ  ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์„ ์„ค๋ช…ํ•˜๊ณ  ์šฐ๋ฆฌ๊ฐ€ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์„ ์ •ํ™•ํ•˜๊ฒŒ ๋„์ถœํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๋ฉด์„œ ์ด๋ฒˆ ์ฃผ๋ง์— ๋ง ๊ทธ๋Œ€๋กœ ๋ช‡ ์‹œ๊ฐ„์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

์ดํ•ด์˜ ๋ถ€์กฑ๊ณผ ๊ณ ๋ ค๋ฅผ ๊ฑฐ๋ถ€ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ˜ผ๋™ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

์ดํ•ด๊ฐ€ ๋ถ€์กฑํ•ด๋„ ๊ดœ์ฐฎ์ง€๋งŒ ํ˜„์žฌ ์ƒํ™ฉ์€ ํฌ๋ง์ด ์—†์–ด ๋ณด์ž…๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๋Š” ํ† ๋ก ์˜ ๋งจ ์ฒ˜์Œ์— ๋งŒ๋“ค์–ด์ง„ ์š”์ ์— ๋Œ€ํ•ด ์—ฌ์ „ํžˆ ํ† ๋ก ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ๊ด€์ ์—์„œ, ๋‚˜๋Š” ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์งˆ๋ฌธ์— ๋‹ตํ•˜๋Š” ์ƒ์„ธํ•œ ์„ค๋ช…์„ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋ช‡ ์‹œ๊ฐ„์„ ๋ณด๋‚ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋Š๊ปด์ง€์ง€๋งŒ ๋‚ด ์˜๊ฒฌ์€ ๋ฌด์‹œ๋˜๊ณ  ๊ฐ™์€ ์งˆ๋ฌธ์ด ๋‹ค์‹œ ์งˆ๋ฌธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ํ˜„์žฌ ๊ตฌ๋ฌธ์˜ ๊ฐ€๋…์„ฑ ๋ถ€์กฑ์ด ๋…ผ์˜์˜ ์ค‘์‹ฌ์— ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋ฅผ ๋’ท๋ฐ›์นจํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€๋…์„ฑ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋ช‡ ๊ฐ€์ง€ ๋ถ„์„์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ถ„์„์—๋Š” ์ƒ๋‹นํ•œ ์ˆ˜์˜ ๐Ÿ‘๊ฐ€ ์žˆ๊ณ  ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๋„ ๋™์˜ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ตœ๊ทผ ๋‹ต๋ณ€์— ๋”ฐ๋ฅด๋ฉด ๊ฐ€๋…์„ฑ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. https://github.com/flutter/flutter/issues/51752#issuecomment -671009593

๋˜ํ•œ ๋‹ค์Œ์„ ์ œ์•ˆํ–ˆ์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  var result = Text('result:');
  var builder1 = (BuildContext context, AsyncSnapshot<int> snapshot) {
    return Row(children: [result, Text(snapshot.data)]);
  };
  result = StreamBuilder(stream: _stream1, builder: builder1);
  var builder2 = (BuildContext context, AsyncSnapshot<int> snapshot) {
    return Column(children: [result, Text(snapshot.data)]);
  };
  result = StreamBuilder(stream: _stream2, builder: builder2);
}

์ฝ์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ 

์ด ๋‘ ๊ฐ€์ง€ ์˜๊ฒฌ์—์„œ ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๋ก ์„ ๋‚ด๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊ฐ€๋…์„ฑ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๊ฐ€๋…์„ฑ์ด ์ด ๋ฌธ์ œ์˜ ๋ฒ”์œ„์— ์†ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋Š” ์—ฌ์ „ํžˆ ๋ถˆ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ์˜ ์œ ์ผํ•œ ๋ชฉ์ ์ด ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ์„ฑ์ด ์ตœ๊ณ ์กฐ์— ๋‹ฌํ•˜์ง€๋งŒ ๊ฐ€๋…์„ฑ/์“ฐ๊ธฐ์„ฑ์ด ์ข‹์ง€ ์•Š์€ ๋นŒ๋”์˜ ๊ตฌ๋ฌธ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์ž„์„ ๊ณ ๋ คํ•˜๋ฉด ๋“ฃ๊ธฐ์— ๋‚™๋‹ด์ž…๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๊ฐ€ ๊ทธ๋Ÿฌํ•œ ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์‹ค์— ๋™์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์šฐ๋ฆฌ๊ฐ€ ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ์„์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Hixie ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ท€ํ•˜์˜ ๊ด€์ ์„ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋งŽ์€ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๋“ค์ด ์ฝ”๋“œ ๋งˆ์ˆ ๋กœ ๋„ˆ๋ฌด ์ง€๋‚˜์ณค์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€๋งŒ ์ ์–ด๋„ ๊ทธ๋“ค์ด ์˜ณ์•˜๋˜ ๊ฒƒ์€ ๋ช‡ ๊ฐ€์ง€ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ €๋Š” Flutter์˜ ๊ณ„์ธตํ™”๋œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋งค์šฐ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค. ์œ„์ ฏ์„ ๊ณ„์† ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์•„๋งˆ๋„ ๋Œ€๋‹ต์€ Dart & Flutter์˜ ํ™•์žฅ์„ฑ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ €์—๊ฒŒ ๋‹ค์Œ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ ์ƒ์„ฑ์„ ๋ณด๋‹ค ์›ํ™œํ•˜๊ฒŒ ํ•˜์„ธ์š”. Dart์—์„œ SwiftUI ๋งˆ๋ฒ•์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ํ•„์š”ํ•œ ์ผ๋ฐ˜์ ์ธ ์„ค์ •์€ ๋„ˆ๋ฌด ํฌ๊ณ  ๋„ˆ๋ฌด ๋Š๋ฆฝ๋‹ˆ๋‹ค.

์ฝ”๋“œ ์ƒ์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํŒจํ‚ค์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์ผ๋ถ€ ์ฃผ์„์„ ๋‘๋“œ๋ฆฌ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๊ฐ„๋‹จํ•˜๋‹ค๋ฉด ๋…ผ์˜๋œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์€ ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ณ  ๋ถˆํ‰์„ ๋ฉˆ์ถœ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€๋Š” ๊ณ„์†ํ•ด์„œ ์ข‹์€ ์˜ค๋ž˜๋œ StatefulWidget์„ ์ง์ ‘ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํŽธ์ง‘: flutter generate ๋Š” ์ข‹์€ ๋ฐฉํ–ฅ์œผ๋กœ ๋‚˜์•„๊ฐ€๋Š” ๋‹จ๊ณ„๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ œ๊ฑฐ๋œ ๊ฒƒ์€ ๋ถ€๋„๋Ÿฌ์šด ์ผ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ Flutter ๊ฐœ๋ฐœ์ž ์„ค๋ฌธ์กฐ์‚ฌ์—์„œ ์ด๊ฒƒ์ด ๋งค์šฐ ํฅ๋ฏธ๋กœ์šด ์งˆ๋ฌธ์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ข‹์€ ์‹œ์ž‘์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฅธ ๋ถ€๋ถ„/์งˆ๋ฌธ์œผ๋กœ ๋‚˜๋ˆ„๊ณ  ์ด๊ฒƒ์ด Flutter ๊ฐœ๋ฐœ์ž๊ฐ€ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ์‹ค์ œ ๋ฌธ์ œ์ธ์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

๋ช…ํ™•ํ•ด์ง€๋ฉด ์ด ๋Œ€ํ™”๊ฐ€ ๋” ์œ ์ฐฝํ•˜๊ณ  ํ’๋ถ€ํ•ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด ๊ด€์ ์—์„œ, ๋‚˜๋Š” ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์งˆ๋ฌธ์— ๋‹ตํ•˜๋Š” ์ƒ์„ธํ•œ ์„ค๋ช…์„ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋ช‡ ์‹œ๊ฐ„์„ ๋ณด๋‚ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋Š๊ปด์ง€์ง€๋งŒ ๋‚ด ์˜๊ฒฌ์€ ๋ฌด์‹œ๋˜๊ณ  ๊ฐ™์€ ์งˆ๋ฌธ์ด ๋‹ค์‹œ ์งˆ๋ฌธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฐ™์€ ์งˆ๋ฌธ์„ ํ•˜๋Š” ๊ฒƒ์€ ๋‹ต์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ด์ „ ๋Œ“๊ธ€(https://github.com/flutter/flutter/issues/51752#issuecomment-670959424)๋กœ ๋Œ์•„๊ฐ€๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋…ผ์˜๋œ ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  return ValueListenableBuilder<String>(
    valueListenable: someValueListenable,
    builder: (context, value, _) {
      return StreamBuilder<int>(
        stream: someStream,
        builder: (context, value2) {
          return TweenAnimationBuilder<double>(
            tween: Tween(...),
            builder: (context, value3) {
              return Text('$value $value2 $value3');
            },
          );
        },
      );
    },
  );
}

์ด ์ฝ”๋“œ๋Š” ์ฝ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ฝ์„ ์ˆ˜์—†๋Š” ๊ฒƒ์„ ์ •๋ง๋กœ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ •ํ™•ํ•˜๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋„ค ๊ฐœ์˜ ์œ„์ ฏ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์„ธ ๊ฐœ์˜ ์œ„์ ฏ์—๋Š” ๋นŒ๋” ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๊ณ , ํ•˜๋‚˜๋Š” ๋ฌธ์ž์—ด๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์œ ํ˜•์„ ์ƒ๋žตํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๊ฐ€ ๋ชจ๋‘ ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ฝ๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์šธ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค.

์ฝ์„ ์ˆ˜ ์—†๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋ถ„๋ช…ํžˆ ๋ง์”€๋“œ๋ฆฌ์ž๋ฉด, ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ ์ฝ์„ ์ˆ˜ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ํ‹€๋ ธ๋‹ค๊ณ  ๋งํ•˜๋ ค๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์™œ ๊ทธ๋Ÿฐ์ง€ ์ดํ•ด๊ฐ€ ์•ˆ๋ฉ๋‹ˆ๋‹ค.

๊ตฌ๋ฌธ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•˜๋Š” ์ƒˆ ํ‚ค์›Œ๋“œ๋ฅผ ๋„์ž…ํ•˜์—ฌ ๊ฐ€๋…์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  final value = keyword ValueListenableBuilder(valueListenable: someValueListenable);
  final value2 = keyword StreamBuilder(stream: someStream);
  final value3 = keyword TweenAnimationBuilder(tween: Tween(...));

  return Text('$value $value2 $value3');
}

์ด ์ฝ”๋“œ๋Š” ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฝ๊ณ  ํ›„ํฌ์™€ ๊ด€๋ จ์ด ์—†์œผ๋ฉฐ ์ œํ•œ ์‚ฌํ•ญ์ด ์—†์Šต๋‹ˆ๋‹ค.

ํ™•์‹คํžˆ ๋œ ์žฅํ™ฉํ•ฉ๋‹ˆ๋‹ค. ์ ์–ด๋„ ๋‚˜์—๊ฒŒ๋Š” ๋” ์ด์ƒ ์ฝ์„ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ๊ฐœ๋…์ด ์žˆ์Šต๋‹ˆ๋‹ค(์ด์ œ ์œ„์ ฏ๊ณผ ์ด "ํ‚ค์›Œ๋“œ" ๊ธฐ๋Šฅ์ด ๋ชจ๋‘ ์žˆ์Šต๋‹ˆ๋‹ค). ๋” ๋งŽ์€ ๊ฐœ๋…์€ ๋” ๋งŽ์€ ์ธ์ง€ ๋ถ€ํ•˜๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. (๋˜ํ•œ ์ด๋Ÿฌํ•œ ๊ฐ์ฒด๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋…๋ฆฝ์ ์ธ์ง€์— ๋”ฐ๋ผ ์ž ์žฌ์ ์œผ๋กœ ๋œ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ํ•ญ์ƒ ์ฒญ์ทจ ๊ฐ€๋Šฅ ๋ฐ ์ŠคํŠธ๋ฆผ ๊ฐ’๋ณด๋‹ค ๋” ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์œผ๋กœ ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š๋”๋ผ๋„ ์ด์ œ ValueListenableBuilder ๋ฐ StreamBuilder๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค. ; ๋˜ํ•œ ์ดˆ๊ธฐํ™” ๋…ผ๋ฆฌ๋Š” ์ด์ œ ๋ชจ๋“  ๋นŒ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๊ฑด๋„ˆ๋›ฐ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.)

๋‹น์‹ ์€ ์žฅํ™ฉํ•œ ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ๋งํ–ˆ์œผ๋ฏ€๋กœ ๋” ๊ฐ„๊ฒฐํ•˜๋‹ค๊ณ  ํ•ด์„œ ๋” ์ฝ๊ธฐ ์‰ฌ์šด ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ œ ์ƒ๊ฐ์—๋Š” (๋‹น์‹ ์ด ๋ฌธ์ œ ์ œ๋ชฉ์— "๋„ˆ๋ฌด ์žฅํ™ฉํ•˜๋‹ค"๋ฅผ ์ž…๋ ฅํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ €๋„ ์ด๊ฒƒ์— ๋Œ€ํ•ด ํ˜ผ๋ž€์Šค๋Ÿฝ๊ธด ํ•˜์ง€๋งŒ ๋ฌธ์ œ์˜ ์›๋ž˜ ์„ค๋ช…). ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ๋œ ํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ๋ง์”€ํ•˜์…จ์ง€๋งŒ, ๋“ค์—ฌ์“ฐ๊ธฐ ์—†์ด ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ„์ „๋„ ์ฝ์„ ์ˆ˜ ์—†๋‹ค๊ณ  ์„ค๋ช…ํ•˜์…จ์œผ๋‹ˆ, ์•„๋งˆ๋„ ์›๋ณธ์˜ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋นŒ๋”๊ฐ€ ์žฌ์‚ฌ์šฉ์„ฑ์˜ ์ •์ ์ด๊ณ  ๋Œ€์ฒด ๊ตฌ๋ฌธ์„ ์›ํ•˜์ง€๋งŒ ์ œ์•ˆํ•œ ์ œ์•ˆ์€ ๋นŒ๋”์™€ ๊ฐ™์ง€ ์•Š์œผ๋ฏ€๋กœ(์œ„์ ฏ์ด๋‚˜ ์š”์†Œ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์Œ) ๋นŒ๋” ์ธก๋ฉด์ด ํŠน๋ณ„ํžˆ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฅผ ์ฐพ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š” (Hooks) ์†”๋ฃจ์…˜์ด ์žˆ์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์ด Hooks๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๊นŒ? ์‚ฌ๋žŒ๋“ค์ด Hooks๋ฅผ ํŒจํ‚ค์ง€๋กœ ์‚ฌ์šฉํ•  ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ข‹์•„ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ”„๋ ˆ์ž„์›Œํฌ์—๋„ ์ข‹์€ ์†”๋ฃจ์…˜์ด ์•„๋‹ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. Flutter ํŒ€์€ ๊ฐ€์น˜ ์žˆ๋Š” ๊ฒƒ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋” ์‰ฌ์šด ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์— ๋Œ€ํ•œ ์š•๊ตฌ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ๋ฌด์Šจ ๋œป์ธ์ง€ ๋ชจ๋ฅด๊ฒ ์–ด์š”.

๋‹ค์Œ์€ ์œ„์˜ ๋‘ ๋ฒ„์ „๊ณผ ๊ฐ€๋…์„ฑ ๋ฉด์—์„œ ์–ด๋–ป๊ฒŒ ๋น„๊ต๋ฉ๋‹ˆ๊นŒ?

Widget build(context) {
  return
    ValueListenableBuilder(valueListenable: someValueListenable, builder: (context, value, _) =>
    StreamBuilder(stream: someStream, builder: (context, value2) =>
    TweenAnimationBuilder(tween: Tween(...), builder: (context, value3) =>
    Text('$value $value2 $value3'),
  )));
}

@szotp ํ˜„์žฌ codegen ์†”๋ฃจ์…˜๊ณผ ๊ด€๋ จํ•˜์—ฌ ๋„ˆ๋ฌด ๋งŽ์€ ๋งˆ์ฐฐ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ฃผ์ €ํ•˜์ง€ ๋ง๊ณ  ๋ฒ„๊ทธ๋ฅผ

@jamesblasco ์—ฌ๊ธฐ์— ์‚ฌ๋žŒ๋“ค์ด ํ•ด๊ฒฐํ•˜๊ธฐ๋ฅผ ์›ํ•˜๋Š” ์‹ค์ œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๋ฐ๋Š” ์˜์‹ฌ์˜ ์—ฌ์ง€๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ €์—๊ฒŒ ์งˆ๋ฌธ์€ ๋ฐ”๋กœ ๊ทธ ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ์†”๋ฃจ์…˜์„ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ ๊ฒฐํ•จ์— ๋Œ€ํ•œ ์šฐ๋ ค๋‚˜ ์ฝ”๋“œ์— ํฌํ•จ๋˜๊ธฐ๋ฅผ ์›ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์šฐ๋ ค์— ๋‹ตํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ์ง€๊ธˆ์€ ๊ทธ๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ์ง‘์ค‘ํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋จผ์ € ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ๋™์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ๋‹ค๋ฅธ ์ฃผ์ œ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ๋™์˜ํ•  ์ˆ˜ ์žˆ์„์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ฝ์„ ์ˆ˜์—†๋Š” ๊ฒƒ์„ ์ •๋ง๋กœ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ •ํ™•ํ•˜๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋„ค ๊ฐœ์˜ ์œ„์ ฏ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์„ธ ๊ฐœ์˜ ์œ„์ ฏ์—๋Š” ๋นŒ๋” ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๊ณ , ํ•˜๋‚˜๋Š” ๋ฌธ์ž์—ด๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์œ ํ˜•์„ ์ƒ๋žตํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๊ฐ€ ๋ชจ๋‘ ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ฝ๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์šธ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฌธ์ œ์˜ ํฐ ๋ถ€๋ถ„์€ ์ฝ”๋”ฉ ๋ฐฉ์‹์ด ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋žŒ๋“ค์ด ์ฝ”๋”ฉํ•˜๋Š” ๋ฐฉ์‹๊ณผ ํฌ๊ฒŒ ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด Flutter์™€ ๊ท€ํ•˜๊ฐ€ ์ œ๊ณตํ•œ ์•ฑ ์˜ˆ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • dartfmt๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค
  • always_specify_types ์‚ฌ์šฉ

์ด ๋‘ ๊ฐ€์ง€ ํฌ์ธํŠธ๋งŒ์œผ๋กœ ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ 1% ์ด์ƒ์„ ๋Œ€ํ‘œํ•œ๋‹ค๋ฉด ๋†€๋ž„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋‹น์‹ ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ‰๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋žŒ๋“ค์ด ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ๊ณผ๋Š” ๋งค์šฐ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ฝ์„ ์ˆ˜์—†๋Š” ๊ฒƒ์„ ์ •๋ง๋กœ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ •ํ™•ํ•˜๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋„ค ๊ฐœ์˜ ์œ„์ ฏ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์„ธ ๊ฐœ์˜ ์œ„์ ฏ์—๋Š” ๋นŒ๋” ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๊ณ , ํ•˜๋‚˜๋Š” ๋ฌธ์ž์—ด๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์œ ํ˜•์„ ์ƒ๋žตํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๊ฐ€ ๋ชจ๋‘ ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ฝ๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์šธ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค.

์ฝ์„ ์ˆ˜ ์—†๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‚ด ์ถ”์ฒœ์€ ํŠน์ • ํ•ญ๋ชฉ์„ ๊ฒ€์ƒ‰ํ•  ๋•Œ ๋ˆˆ์ด ๋ณด๊ณ  ์žˆ๋Š” ์œ„์น˜์™€ ๊ฑฐ๊ธฐ์— ๋„๋‹ฌํ•˜๋Š” ๋ฐ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋‹จ๊ณ„๊ฐ€ ํ•„์š”ํ•œ์ง€ ๋ถ„์„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์‹คํ—˜์„ ํ•ด๋ณด์ž:
๋‘ ๊ฐœ์˜ ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ์ œ๊ณตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ์„ ํ˜• ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ์ค‘์ฒฉ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
๋˜ํ•œ ํ•ด๋‹น ์Šค ๋‹ˆํŽซ์—์„œ ์ฐพ์•„์•ผ ํ•  ํŠน์ • ์‚ฌํ•ญ์„ ์•Œ๋ ค ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

์„ ํ˜• ๊ตฌ๋ฌธ ๋˜๋Š” ์ค‘์ฒฉ ๊ตฌ๋ฌธ ์‚ฌ์šฉ์— ๋Œ€ํ•œ ๋‹ต์„ ์ฐพ๋Š” ๊ฒƒ์ด ๋” ์‰ฝ์Šต๋‹ˆ๊นŒ?

์งˆ๋ฌธ:

  • ์ด ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ์—์„œ ๋ฐ˜ํ™˜๋œ ๋น„๋นŒ๋” ์œ„์ ฏ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
  • bar ๋ณ€์ˆ˜๋Š” ๋ˆ„๊ฐ€ ์ƒ์„ฑํ•ฉ๋‹ˆ๊นŒ?
  • ์šฐ๋ฆฌ๋Š” ๋ช‡ ๋ช…์˜ ๊ฑด์ถ•์—…์ž๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

๋นŒ๋” ์‚ฌ์šฉ:

 ์œ„์ ฏ ๋นŒ๋“œ(์ปจํ…์ŠคํŠธ) {
 ValueListenableBuilder ๋ฐ˜ํ™˜(
 valueListenable: someValueListenable,
 ๋นŒ๋”: (context, foo, _) {
 ์ŠคํŠธ๋ฆผ ๋นŒ๋”๋ฅผ ๋ฐ˜ํ™˜(
 ์ŠคํŠธ๋ฆผ: someStream,
 ๋นŒ๋”: (์ปจํ…์ŠคํŠธ, baz) {
 TweenAnimationBuilder ๋ฐ˜ํ™˜(
 ํŠธ์œˆ: ํŠธ์œˆ(...),
 ๋นŒ๋”: (์ปจํ…์ŠคํŠธ, ๋ฐ”) {
 ๋ฐ˜ํ™˜ Container();
 },
 );
 },
 );
 },
 );
 }

์„ ํ˜• ๊ตฌ๋ฌธ ์‚ฌ์šฉ:

 ์œ„์ ฏ ๋นŒ๋“œ(์ปจํ…์ŠคํŠธ) {
 ์ตœ์ข… foo = ํ‚ค์›Œ๋“œ ValueListenableBuilder(valueListenable: someValueListenable);
 ์ตœ์ข… ๋ง‰๋Œ€ = ํ‚ค์›Œ๋“œ StreamBuilder(์ŠคํŠธ๋ฆผ: someStream);
 ์ตœ์ข… baz = ํ‚ค์›Œ๋“œ TweenAnimationBuilder(tween: Tween(...));

๋ฐ˜ํ™˜ ์ด๋ฏธ์ง€(); }


์ œ ๊ฒฝ์šฐ์—๋Š” ๋‹ต์„ ์ฐพ๊ธฐ ์œ„ํ•ด ์ค‘์ฒฉ๋œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ์ด ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
๋ฐ˜๋ฉด์— ์„ ํ˜• ํŠธ๋ฆฌ๋กœ ๋‹ต์„ ์ฐพ๋Š” ๊ฒƒ์€ ์ฆ‰๊ฐ์ ์ž…๋‹ˆ๋‹ค.

๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ๋œ ํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ๋ง์”€ํ•˜์…จ์ง€๋งŒ, ๋“ค์—ฌ์“ฐ๊ธฐ ์—†์ด ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ„์ „๋„ ์ฝ์„ ์ˆ˜ ์—†๋‹ค๊ณ  ์„ค๋ช…ํ•˜์…จ์œผ๋‹ˆ, ์•„๋งˆ ์›๋ณธ์˜ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

StreamBuilder๊ฐ€ ์—ฌ๋Ÿฌ ๋ณ€์ˆ˜๋กœ ๋ถ„ํ• ๋œ ๊ฒƒ์ด ์‹ฌ๊ฐํ•œ ์ œ์•ˆ์ด์—ˆ์Šต๋‹ˆ๊นŒ?
๋‚ด๊ฐ€ ์ดํ•ดํ•œ ๋ฐ”์— ๋”ฐ๋ฅด๋ฉด ์ด๊ฒƒ์€ ๋…ผ์Ÿ์„ ๋ฒŒ์ด๋ ค๋Š” ๋น„๊ผฌ๋Š” ์ œ์•ˆ์ด์—ˆ๋‹ค. ์•„๋‹ˆ์—ˆ๋‚˜์š”? ์ด ํŒจํ„ด์ด ํฐ ์œ„์ ฏ์—์„œ๋„ ๋” ์ฝ๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ๋กœ ์ด์–ด์งˆ ๊ฒƒ์ด๋ผ๊ณ  ์ •๋ง๋กœ ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ?

์˜ˆ์ œ๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ฌด์‹œํ•˜๊ณ  ์™œ ์ฝ์„ ์ˆ˜ ์—†๋Š”์ง€ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์ œ๋ฅผ ๋ถ„ํ•ดํ•˜๋Š” ๋ฐ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ๊ฐ€์น˜๊ฐ€ ์žˆ์„๊นŒ์š”?

```๋‹คํŠธ
์œ„์ ฏ ๋นŒ๋“œ(์ปจํ…์ŠคํŠธ) {
๋ฐ˜ํ’ˆ
ValueListenableBuilder(valueListenable: someValueListenable, builder: (context, value, _) =>
StreamBuilder(์ŠคํŠธ๋ฆผ: someStream, ๋นŒ๋”: (context, value2) =>
TweenAnimationBuilder(tween: Tween(...), builder: (context, value3) =>
ํ…์ŠคํŠธ('$๊ฐ’ $๊ฐ’2 $๊ฐ’3'),
)));
}

๊ทธ๊ฒŒ ๋” ์ข‹์•„ ๋ณด์ธ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์‚ฌ๋žŒ๋“ค์ด dartfmt๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค

dartfmt๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  return ValueListenableBuilder(
      valueListenable: someValueListenable,
      builder: (context, value, _) => StreamBuilder(
          stream: someStream,
          builder: (context, value2) => TweenAnimationBuilder(
                tween: Tween(),
                builder: (context, value3) => Text('$value $value2 $value3'),
              )));
}

์›๋ž˜ ์ฝ”๋“œ์™€ ๊ฑฐ์˜ ๋‹ค๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋นŒ๋”๊ฐ€ ์žฌ์‚ฌ์šฉ์„ฑ์˜ ์ •์ ์ด๊ณ  ๋Œ€์ฒด ๊ตฌ๋ฌธ์„ ์›ํ•˜์ง€๋งŒ ์ œ์•ˆํ•œ ์ œ์•ˆ์€ ๋นŒ๋”์™€ ๊ฐ™์ง€ ์•Š์œผ๋ฏ€๋กœ(์œ„์ ฏ์ด๋‚˜ ์š”์†Œ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์Œ) ๋นŒ๋” ์ธก๋ฉด์ด ํŠน๋ณ„ํžˆ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฅผ ์ฐพ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.
์š”์†Œ๊ฐ€ ์žˆ๋Š”์ง€ ์—†๋Š”์ง€์— ๋Œ€ํ•œ ํŠน๋ณ„ํ•œ ์ด์œ ๋Š” ์—†์Šต๋‹ˆ๋‹ค.
์‚ฌ์‹ค, LayoutBuilder ๋ฐ ์ž ์žฌ์ ์œผ๋กœ GestureDetector ํฌํ•จํ•  ์ˆ˜ ์žˆ๋„๋ก ์š”์†Œ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ํฅ๋ฏธ๋กœ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ React ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๋‹ค์–‘ํ•œ ํ›„ํฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘์—์„œ ๋‹ค์Œ์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

  • useIsHovered โ€“ ์œ„์ ฏ์ด ํ˜ธ๋ฒ„๋ง๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ๋ถ€์šธ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • useSize โ€“ ์—ฐ๊ฒฐ๋œ UI์˜ ํฌ๊ธฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” (Flutter์˜ useContraints์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.)

(๋˜ํ•œ ์ด๋Ÿฌํ•œ ๊ฐ์ฒด๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋…๋ฆฝ์ ์ธ์ง€์— ๋”ฐ๋ผ ์ž ์žฌ์ ์œผ๋กœ ๋œ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ํ•ญ์ƒ ์ฒญ์ทจ ๊ฐ€๋Šฅ ๋ฐ ์ŠคํŠธ๋ฆผ ๊ฐ’๋ณด๋‹ค ๋” ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์œผ๋กœ ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š๋”๋ผ๋„ ์ด์ œ ValueListenableBuilder ๋ฐ StreamBuilder๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค. ; ๋˜ํ•œ ์ดˆ๊ธฐํ™” ๋…ผ๋ฆฌ๋Š” ์ด์ œ ๋ชจ๋“  ๋นŒ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๊ฑด๋„ˆ๋›ฐ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.)

๊ทธ๊ฒƒ์€ ์†”๋ฃจ์…˜์ด ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐ๋˜๋Š”์ง€์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์–ธ์–ด ์ˆ˜์ •์„ ์œ„ํ•ด ๊ฐ„๋‹ค๋ฉด ์ด ๋ฌธ์ œ๋Š” ์ „ํ˜€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Widget build(context) {
  final value = keyword ValueListenableBuilder(valueListenable: someValueListenable);
  final value2 = keyword StreamBuilder(stream: someStream);
  final value3 = keyword TweenAnimationBuilder(tween: Tween(...));

  return Text('$value $value2 $value3');
}

"์ปดํŒŒ์ผ":

Widget build(context) {
  return ValueListenableBuilder<String>(
    valueListenable: someValueListenable,
    builder: (context, value, _) {
      return StreamBuilder<int>(
        stream: someStream,
        builder: (context, value2) {
          return TweenAnimationBuilder<double>(
            tween: Tween(...),
            builder: (context, value3) {
              return Text('$value $value2 $value3');
            },
          );
        },
      );
    },
  );
}

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ flutter_hooks์—๋Š” HookBuilder ์œ„์ ฏ์ด ์ œ๊ณต๋˜๋ฏ€๋กœ ํ•„์š”ํ•  ๋•Œ ์—ฌ์ „ํžˆ ๋ถ„ํ• ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ํŠนํžˆ ์—ฌ๊ธฐ์—์„œ ๋งŒ๋“  ์˜ˆ์—์„œ ์‹ค์ œ๋กœ ๋ฌธ์ œ์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•˜๋ ค๋ฉด ์ ์ ˆํ•œ ๋ฒค์น˜๋งˆํฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ์š”์†Œ๋งŒ ๋‹ค์‹œ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.
๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์žฌ๊ตฌ์ถ•์ด ์—ฌ๋Ÿฌ ์š”์†Œ๋กœ ๋ถ„ํ• ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์ž‘๋”๋ผ๋„ ์•ฝ๊ฐ„์˜ ์˜ค๋ฒ„ ํ—ค๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ํ›„ํฌ๋ฅผ ์žฌํ‰๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋น ๋ฅผ ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด React ํŒ€์ด hook์„ ๋””์ž์ธํ•  ๋•Œ ์ƒ๊ฐํ•ด ๋‚ธ ๊ฒฐ๋ก ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ Flutter์—๋Š” ์ ์šฉ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ์„ ์ˆ˜ ์—†๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ค‘์ฒฉ์œผ๋กœ ์ธํ•ด ์ค‘์ฒฉ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋น ๋ฅด๊ฒŒ ์Šค์บ”ํ•˜๊ณ  ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„๊ณผ ์ง„ํ–‰ ์ค‘์ธ ์ž‘์—…์„ ์ดํ•ดํ•˜๋Š” ๋ฐ ํ•„์ˆ˜์ ์ธ ๋ถ€๋ถ„์„ ํŒŒ์•…ํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ๋ณธ์งˆ์ ์œผ๋กœ "์ˆœ์ฐจ์ "์ด์ง€๋งŒ ์ค‘์ฒฉ์€ ์ด๋ฅผ ์ˆจ๊น๋‹ˆ๋‹ค. ๋˜ํ•œ ์ค‘์ฒฉ์€ ์ž‘์—…์„ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋‘ ํ•ญ๋ชฉ์„ ์žฌ์ •๋ ฌํ•˜๊ฑฐ๋‚˜ ๋‘ ํ•ญ๋ชฉ ์‚ฌ์ด์— ์ƒˆ ํ•ญ๋ชฉ์„ ์‚ฝ์ž…ํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ์ƒ์ƒํ•ด๋ณด์„ธ์š”. ์ˆœ์ฐจ ์ฝ”๋“œ์—์„œ๋Š” ์‚ฌ์†Œํ•˜์ง€๋งŒ ์ค‘์ฒฉ ์ž‘์—…์ด ํ•„์š”ํ•  ๋•Œ๋Š” ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ async/await ์„คํƒ•๊ณผ ์›์‹œ Future API๋กœ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•˜๋ฉฐ, ์•„๋ž˜์— ์žˆ๋Š” dame ์—ฐ์† ๊ธฐ๋ฐ˜ ๊ฐœ๋…(๊ทธ๋ฆฌ๊ณ  ์ฐฌ์„ฑ ๋ฐ ๋ฐ˜๋Œ€ ์ธ์ˆ˜๋„ ๋งค์šฐ ์œ ์‚ฌํ•จ) - ์˜ˆ Future API๋Š” ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์•„๋ฌด ๊ฒƒ๋„ ์ˆจ๊ธฐ์ง€ ์•Š์ง€๋งŒ ๊ฐ€๋…์„ฑ ๋ฐ ์œ ์ง€ ๊ด€๋ฆฌ ์šฉ์ด์„ฑ ํ™•์‹คํžˆ ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค. async/wait๊ฐ€ ์Šน์ž์ž…๋‹ˆ๋‹ค.

๋‚ด ์ถ”์ฒœ์€ ํŠน์ • ํ•ญ๋ชฉ์„ ๊ฒ€์ƒ‰ํ•  ๋•Œ ๋ˆˆ์ด ๋ณด๊ณ  ์žˆ๋Š” ์œ„์น˜์™€ ๊ฑฐ๊ธฐ์— ๋„๋‹ฌํ•˜๋Š” ๋ฐ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋‹จ๊ณ„๊ฐ€ ํ•„์š”ํ•œ์ง€ ๋ถ„์„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ €๋Š” 25๋…„ ๋™์•ˆ 10๊ฐœ ์ด์ƒ์˜ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•ด์™”์œผ๋ฉฐ, ์ด๋Š” ์ฝ”๋“œ๋ฅผ ๊ฐ€๋…์„ฑ ์žˆ๊ฒŒ ๋งŒ๋“œ๋Š” ์š”์†Œ๋ฅผ ํ‰๊ฐ€ํ•˜๋Š” ๊ฐ€์žฅ ๋‚˜์œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์†Œ์Šค ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์€ ๊นŒ๋‹ค๋กญ์ง€๋งŒ "๋‚ด ๋ˆˆ์ด ๋ณด๋Š” ๊ณณ"์ด๋‚˜ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ ์ค„ ์ˆ˜๋ณด๋‹ค ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐœ๋…๊ณผ ๋…ผ๋ฆฌ๋ฅผ ์–ผ๋งˆ๋‚˜ ์ž˜ ํ‘œํ˜„ํ•˜๋Š๋ƒ๊ฐ€ ๋” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋˜๋Š” ์˜คํžˆ๋ ค ๊ฐ€๋…์„ฑ์— ๋„ˆ๋ฌด ์ง‘์ค‘ํ•˜๊ณ  ์œ ์ง€ ๊ด€๋ฆฌ์— ๋œ ์ง‘์ค‘ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ์˜ __intent__๊ฐ€ ๋œ ๋ช…ํ™•ํ•˜๊ณ  ๋™์ผํ•œ ์œ„์น˜์— ์ˆจ๊ฒจ์ง„ ๋‹ค๋ฅธ ๊ด€์‹ฌ์‚ฌ๋กœ ์ธํ•ด ์œ ์ง€ ๊ด€๋ฆฌ๊ฐ€ ๋” ์–ด๋ ค์›Œ์ง€๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์ œ๋Š” ๋œ ์ฝ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.


final value = keyword ValueListenableBuilder(valueListenable: someValueListenable);

๊ทธ ๊ฐ€์น˜๋Š” ์–ผ๋งˆ๋‚˜ ๋ ๊นŒ์š”? ์œ„์ ฏ? ๋ฌธ์ž์—ด ๋ณ€์ˆ˜? ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค
return Text('$value $value2 $value3');

๊ธฐ๋ณธ์ ์œผ๋กœ ์›ํ•˜๋Š” ๊ฒƒ์€ ์œ„์ ฏ B์˜ ๋นŒ๋“œ ๋ฉ”์„œ๋“œ์—์„œ ๋ณ€์ˆ˜ A๋ฅผ ์ฐธ์กฐํ•˜์—ฌ A ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค B๊ฐ€ ๋‹ค์‹œ ๋นŒ๋“œ๋˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋ง ๊ทธ๋Œ€๋กœ mobx๊ฐ€ ํ•˜๋Š” ์ผ์ด๋ฉฐ, ์ ์ ˆํ•œ ์–‘์˜ ๋งˆ๋ฒ•/๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ๋กœ ์ •ํ™•ํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.


final value2 = keyword StreamBuilder(stream: someStream);

์ด๊ฒƒ์€ ๋ฌด์—‡์„ ๋ฐ˜ํ™˜ํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ? ์œ„์ ฏ? ์ŠคํŠธ๋ฆผ? ๋ฌธ์ž์—ด ๊ฐ’?

๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ๊ทธ๊ฒƒ์€ ๋ฌธ์ž์—ด ๊ฐ’์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๋‹จ์ˆœํžˆ ์œ„์ ฏ ์ŠคํŠธ๋ฆผ์ด ๊ฐ’์„ ๋ฐฉ์ถœ ํ•  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ๊ฒƒ์„, ๋นŒ๋“œ ๋ฐฉ๋ฒ•์— ์›์ธ์„ ์ŠคํŠธ๋ฆผ์„ ์ฐธ์กฐํ•˜๊ณ  ๋ฐฉ์ถœ ๊ฐ’์— ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์œ„์ ฏ์ด ์ƒ์„ฑ ๋  ๋•Œ๋งˆ๋‹ค ์ŠคํŠธ๋ฆผ์˜ / ๊ฐฑ์‹  / ํ๊ธฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ•˜๋Š” ๊ทธ๋ž˜์„œ / ์—…๋ฐ์ดํŠธ /ํŒŒ๊ดด๋จ? ํ•œ ์ค„์˜ ์ฝ”๋“œ๋กœ? ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€?

์˜ˆ, mobx๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋นŒ๋“œ ๋ฐฉ๋ฒ•์ด "๊ฐ€๋…์„ฑ์ด ๋” ๋†’์€" ์˜ˆ์ œ์™€ ๋˜‘๊ฐ™์ด ๋ณด์ด๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๊ด€์ธก ๊ฐ€๋Šฅ ํ•ญ๋ชฉ ์ฐธ์กฐ ์ œ์™ธ). ํ›„ํฌ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ์ฝ”๋“œ๋Š” ์•ฝ 10์ค„์ด๋ฉฐ ๋ชจ๋“  ์œ„์ ฏ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


final value3 = keyword TweenAnimationBuilder(tween: Tween(...));

๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” "TweenAnimationBuilder"๋ผ๋Š” ํด๋ž˜์Šค?! ๋‚˜๋Š” ์ด๊ฒƒ์ด ์™œ ๋”์ฐํ•œ ์ƒ๊ฐ์ธ์ง€ ๊ฐ€๊นŒ์ด ๊ฐ€์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค.

๋“ค์—ฌ์“ฐ๊ธฐ/๊ฐ€๋…์„ฑ์—๋Š” ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

Future<double> future;

AsyncSnapshot<double> value = keyword FutureBuilder<double>(future: future);

๊ทธ๋ฆฌ๊ณ :

Future<double> future;

double value = await future;

๋‘˜ ๋‹ค ๋˜‘๊ฐ™์€ ์ผ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๊ฐ์ฒด๋ฅผ ๋“ฃ๊ณ  ๊ฐ’์„ ์–ธ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ฝ์„ ์ˆ˜์—†๋Š” ๊ฒƒ์„ ์ •๋ง๋กœ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ •ํ™•ํ•˜๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋„ค ๊ฐœ์˜ ์œ„์ ฏ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์„ธ ๊ฐœ์˜ ์œ„์ ฏ์—๋Š” ๋นŒ๋” ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๊ณ , ํ•˜๋‚˜๋Š” ๋ฌธ์ž์—ด๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์œ ํ˜•์„ ์ƒ๋žตํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๊ฐ€ ๋ชจ๋‘ ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ฝ๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์šธ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค.

๋™์ผํ•œ ์ฃผ์žฅ์ด Promise/Future ์ฒด์ธ์— ์ ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

foo().then(x =>
  bar(x).then(y =>
    baz(y).then(z =>
      qux(z)
    )
  )
)

๋Œ€

let x = await foo();
let y = await bar(x);
let z = await baz(y);
await qux(z);

์ฒซ ๋ฒˆ์งธ ์ž‘์„ฑ ๋ฐฉ๋ฒ•์€ Promise๊ฐ€ ํ›„๋“œ ์•„๋ž˜์—์„œ ์ƒ์„ฑ๋˜๊ณ  ์žˆ์œผ๋ฉฐ ์ฒด์ธ์ด ์ •ํ™•ํžˆ ์–ด๋–ป๊ฒŒ ํ˜•์„ฑ๋˜๋Š”์ง€๋ฅผ ๋ช…ํ™•ํžˆ ํ•ด์ค€๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ๊ทธ๊ฒƒ์„ ๊ตฌ๋…ํ•˜๋Š”์ง€, ๋˜๋Š” ๋‹น์‹ ์ด ๊ตฌ๋ฌธ์„๋ฐ›์„ ์ž๊ฒฉ์ด ์žˆ๋‹ค๋Š” ์ ์—์„œ ์•ฝ์†์ด ๋นŒ๋”์™€ ๊ทผ๋ณธ์ ์œผ๋กœ ๋‹ค๋ฅด๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” "TweenAnimationBuilder"๋ผ๋Š” ํด๋ž˜์Šค?! ๋‚˜๋Š” ์ด๊ฒƒ์ด ์™œ ๋”์ฐํ•œ ์ƒ๊ฐ์ธ์ง€ ๊ฐ€๊นŒ์ด ๊ฐ€์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค.

Promises/Futures์— ๋Œ€ํ•ด ๋™์ผํ•œ ์ฃผ์žฅ์„ ํ•˜๊ณ  await ๊ฐ€ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ชจํ˜ธํ•˜๊ฒŒ ํ•œ๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌ๋ฌธ์„ ํ†ตํ•ด ์‚ฌ๋ฌผ์„ "ํ’€๊ธฐ"ํ•œ๋‹ค๋Š” ์•„์ด๋””์–ด๋Š” ๊ฑฐ์˜ ์ƒˆ๋กœ์šด ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์˜ˆ, ์ฃผ๋ฅ˜ ์–ธ์–ด์—์„œ๋Š” async/await๋ฅผ ํ†ตํ•ด ์ œ๊ณต๋˜์—ˆ์ง€๋งŒ, ์˜ˆ๋ฅผ ๋“ค์–ด F#์—๋Š” ์ผ๋ถ€ ํ•˜๋“œ์ฝ”์–ด FP ์–ธ์–ด์˜ do ํ‘œ๊ธฐ๋ฒ•๊ณผ ์œ ์‚ฌํ•œ ๊ณ„์‚ฐ ํ‘œํ˜„์‹์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฑฐ๊ธฐ์—์„œ ํ›จ์”ฌ ๋” ๋งŽ์€ ๊ถŒํ•œ์„ ๊ฐ€์ง€๋ฉฐ ํŠน์ • ๋ฒ•๋ฅ ์„ ์ถฉ์กฑํ•˜๋Š” ๋ชจ๋“  ๋ž˜ํผ์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋„๋ก ์ผ๋ฐ˜ํ™”๋ฉ๋‹ˆ๋‹ค. Dart์— Monad๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ๋น„๋™๊ธฐ ํ˜ธ์ถœ์— ๋ฐ˜๋“œ์‹œ ํ•ด๋‹นํ•˜์ง€ ์•Š๋Š” "๋ž˜ํ•‘ ํ•ด์ œ"์— ๋Œ€ํ•œ ์œ ํ˜• ์•ˆ์ „ ๊ตฌ๋ฌธ์— ๋Œ€ํ•œ ์ „๋ก€๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์„ ์–ธ๊ธ‰ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ•œ ๊ฑธ์Œ ๋ฌผ๋Ÿฌ์„œ์„œ, ์—ฌ๊ธฐ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด (์ €๋ฅผ ํฌํ•จํ•˜์—ฌ) ์–ด๋ ค์›€์„ ๊ฒช๊ณ  ์žˆ๋Š” ํ•œ ๊ฐ€์ง€๋Š” ๊ฐ€๋…์„ฑ์— ๋Œ€ํ•œ ์ด ์งˆ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. @rrousselGit ์ด ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ํ˜„์žฌ Builder ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์— ๋Œ€ํ•œ ๊ฐ€๋…์„ฑ ๋ฌธ์ œ์˜ ์ด ์Šค๋ ˆ๋“œ ์ „๋ฐ˜์— ๊ฑธ์ณ ๋งŽ์€ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ์ค‘ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‚ฌ์‹ค์ด ์ž๋ช…ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

Widget build(context) {
  return ValueListenableBuilder<String>(
    valueListenable: someValueListenable,
    builder: (context, value, _) {
      return StreamBuilder<int>(
        stream: someStream,
        builder: (context, value2) {
          return TweenAnimationBuilder<double>(
            tween: Tween(...),
            builder: (context, value3) {
              return Text('$value $value2 $value3');
            },
          );
        },
      );
    },
  );
}

๋‹ค์Œ๋ณด๋‹ค ๊ฐ€๋…์„ฑ์ด ํ˜„์ €ํžˆ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

Widget build(context) {
  final value = keyword ValueListenableBuilder(valueListenable: someValueListenable);
  final value2 = keyword StreamBuilder(stream: someStream);
  final value3 = keyword TweenAnimationBuilder(tween: Tween(...));

  return Text('$value $value2 $value3');
}

๊ทธ๋Ÿฌ๋‚˜ @Hixie ์™€ @Rudiksz ๋Š” ๋‘ ๋ฒˆ์งธ๊ฐ€ ์ฒซ ๋ฒˆ์งธ ๊ฒƒ๋ณด๋‹ค ๋” ์ฝ๊ธฐ ์‰ฝ๋‹ค๋Š” ์•„์ด๋””์–ด์— ํ™•์‹ ์„

๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ์— ๋‘ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก์ด ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก๋ณด๋‹ค ๋” ์ฝ๊ธฐ ์‰ฌ์šด ์ด์œ ์— ๋Œ€ํ•œ ๋‚ด ๋ถ„์„(๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ์ž‘์€ ๊ธˆ์•ก์— ๋Œ€ํ•ด)์ด ์žˆ์Šต๋‹ˆ๋‹ค.

1. ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก์ด ๋‘ ๋ฒˆ์งธ ์ฝ”๋“œ๋ณด๋‹ค ํ›จ์”ฌ ๋” ๋“ค์—ฌ์“ฐ๊ธฐ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด ๋“ค์—ฌ์“ฐ๊ธฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋น„๋™๊ธฐ์‹, ๋ถ„๊ธฐ ๋˜๋Š” ์ฝœ๋ฐฑ๊ณผ ๋™์ผํ•˜๋ฉฐ, ๋ชจ๋‘ ๋“ค์—ฌ์“ฐ๊ธฐ๋˜์ง€ ์•Š์€ ์„ ํ˜• ์ฝ”๋“œ๋ณด๋‹ค ๋” ๋งŽ์€ ์ธ์ง€ ๋ถ€ํ•˜๊ฐ€ โ€‹โ€‹ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก์—๋Š” ์—ฌ๋Ÿฌ ๊ฒน์˜ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ์—์„œ ์ผ์–ด๋‚˜๋Š” ์ผ๊ณผ ๊ถ๊ทน์ ์œผ๋กœ ๋ Œ๋”๋ง๋˜๋Š” ๋‚ด์šฉ(๋‹จ์ผ Text )์„ ์‚ดํŽด๋ณด๋Š” ๋ฐ ์ ์ง€ ์•Š์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์€ ๋งˆ์Œ์†์œผ๋กœ ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ํ†ตํ•ด ์ž‘์—…ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๋‘ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก์—๋Š” ๋ฌธ์ œ๋ฅผ ์™„ํ™”ํ•˜๋Š” ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

2. ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก์€ ์˜๋„๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋” ๋งŽ์€ ๊ตฌ๋ฌธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก์—๋Š” return ๋ฌธ 3๊ฐœ, ๋นŒ๋” ๋ฌธ 3๊ฐœ, ๋žŒ๋‹ค ํ—ค๋” 3๊ฐœ, ์ปจํ…์ŠคํŠธ 3๊ฐœ, ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฐ’ 3๊ฐœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ถ๊ทน์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ๊ด€์‹ฌ์„ ๊ฐ–๋Š” ๊ฒƒ์€ ์ด ์„ธ ๊ฐ€์ง€ ๊ฐ€์น˜์ž…๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€๋Š” ์šฐ๋ฆฌ๋ฅผ ๊ฑฐ๊ธฐ์— ์ด๋ฅด๊ฒŒ ํ•˜๋Š” ์ƒ์šฉ๊ตฌ์ž…๋‹ˆ๋‹ค. ์ €๋Š” ์‹ค์ œ๋กœ ์ด๊ฒƒ์ด ์ด ์ฝ”๋“œ ๋ธ”๋ก์—์„œ ๊ฐ€์žฅ ์–ด๋ ค์šด ๋ถ€๋ถ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ๋งŽ์€ ์ผ์ด ์ง„ํ–‰๋˜๊ณ  ์žˆ๊ณ  ๋‚ด๊ฐ€ ์‹ค์ œ๋กœ ๊ด€์‹ฌ์„ ๊ฐ–๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„(๋นŒ๋”๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’)์€ ๋„ˆ๋ฌด ์ž‘์€ ๋ถ€๋ถ„์ด๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ๋ถ€๋ถ„์— ์ง‘์ค‘ํ•˜๋Š” ๋Œ€์‹  ์ƒ์šฉ๊ตฌ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์ •์‹  ์—๋„ˆ์ง€์˜ ๋Œ€๋ถ€๋ถ„์„ ์†Œ๋น„ํ•ฉ๋‹ˆ๋‹ค( ๋‹ค์‹œ, ๊ฐ’).


๋‘ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก์—๋Š” ์ƒ์šฉ๊ตฌ๊ฐ€ ํฌ๊ฒŒ ์ค„์–ด๋“ค์–ด ๋‚ด๊ฐ€ ๊ด€์‹ฌ ์žˆ๋Š” ๋ถ€๋ถ„, ์ฆ‰ ๊ฐ’์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก์€ ์ค‘์ฒฉ์˜ ๊ฐ€์žฅ ๊นŠ์€ ๋ถ€๋ถ„์—์„œ build ๋ฉ”์„œ๋“œ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์„ ์ˆจ๊น๋‹ˆ๋‹ค.

์ด build ๋ฉ”์„œ๋“œ์˜ ๋ชจ๋“  ๋ถ€๋ถ„์ด ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์ด ์Šคํƒ€์ผ์˜ ์„ ์–ธ์  UI ์ฝ”๋“œ๋ฅผ ์ฝ์„ ๋•Œ ์ผ๋ฐ˜์ ์œผ๋กœ ์ฐพ๊ณ  ์žˆ๋Š” ๊ฒƒ์€ ์ด ๊ฒฝ์šฐ ๊ฐ€์žฅ ๊นŠ์€ ์ค‘์ฒฉ ๋นŒ๋”์— ํฌํ•จ๋œ Text ์œ„์ ฏ์ž…๋‹ˆ๋‹ค. ๊ทธ Text ์œ„์ ฏ์€ ์ „๋ฉด ์ค‘์•™์— ์œ„์น˜ํ•˜์ง€ ์•Š๊ณ  ๋“ค์—ฌ์“ฐ๊ธฐ, ๊ตฌ๋ฌธ ๋ฐ ์˜๋„์˜ ์—ฌ๋Ÿฌ ๋ ˆ์ด์–ด์— ๋ฌปํ˜€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ ˆ์ด์–ด ์ค‘ ํ•˜๋‚˜์— Column ๋˜๋Š” Row ๋ฅผ ๋˜์ง€๋ฉด ํ›จ์”ฌ ๋” ๊นŠ์ด ์ค‘์ฒฉ๋˜๊ณ  ๊ทธ ์‹œ์ ์—์„œ ๊ฐ€์žฅ ๋“ค์—ฌ์“ฐ๊ธฐ๋œ ์„น์…˜์œผ๋กœ ์ถ”์ ํ•˜๋Š” ์ด์ ์กฐ์ฐจ ์—†์Šต๋‹ˆ๋‹ค. .


๋‘ ๋ฒˆ์งธ ์ฝ”๋“œ ๋ธ”๋ก์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” ์‹ค์ œ ๋ Œ๋”๋ง ๊ฐ€๋Šฅ Widget ์€ ํ•จ์ˆ˜์˜ ๋งจ ์•„๋ž˜์— ์žˆ์œผ๋ฉฐ ์ฆ‰์‹œ ๋ช…๋ฐฑํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ œ์•ˆ๋œ ๊ตฌ๋ฌธ OP์™€ ๊ฐ™์€ ๊ฒƒ์ด ์žˆ์„ ๋•Œ ์‹œ๊ฐ์ ์ธ Widget ํ•ญ์ƒ ํ•จ์ˆ˜์˜ ๋งจ ์•„๋ž˜์— ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฝ”๋“œ๋ฅผ ํ›จ์”ฌ ๋” ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ณ  ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์ค‘์ฒฉ๊ณผ ๊ด€๋ จ ํ•˜์—ฌ _tree_ ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์ค‘์ฒฉ๊ณผ _sequence_ ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์ค‘์ฒฉ ์—๋Š” ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ View -> Text ์ค‘์ฒฉ ๋“ฑ์˜ ๊ฒฝ์šฐ ์ค‘์ฒฉ์€ ํ™”๋ฉด์— ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„ ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. Context์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์˜ ๊ฒฝ์šฐ(Flutter์— ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Œ) ์ปจํ…์ŠคํŠธ์˜ ๋ฒ”์œ„๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ค‘์ฒฉ ์ž์ฒด๋Š” ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์— ์ค‘์š”ํ•œ ์˜๋ฏธ๋ก ์  ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๋ฉฐ ๋ฌด์‹œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ถ€๋ชจ์™€ ์ž์‹์˜ ์ž๋ฆฌ๋งŒ ๋ฐ”๊ฟ”์„œ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™์„ ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋นŒ๋”์˜ ์ค‘์ฒฉ(React์˜ "Render Props"๋ผ๊ณ ๋„ ํ•จ) ๋˜๋Š” Promises์˜ ์ค‘์ฒฉ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ค‘์ฒฉ์ด ์ผ๋ จ์˜ ๋ณ€ํ™˜/์ฆ๊ฐ€ ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠธ๋ฆฌ ์ž์ฒด๋Š” ๊ทธ๋‹ค์ง€ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋…๋ฆฝ์ ์ธ ABuilder -> BBuilder -> CBuilder ์ค‘์ฒฉํ•  ๋•Œ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋Š” ์ถ”๊ฐ€ ์˜๋ฏธ๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ๋ฒ”์œ„์—์„œ ์„ธ ๊ฐ€์ง€ ๊ฐ’์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ ํ•ด๋‹น ํŠธ๋ฆฌ ๊ตฌ์กฐ๋Š” ์‹ค์ œ๋กœ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ฐœ๋…์ ์œผ๋กœ๋Š” "ํ‰ํ‰"ํ•˜๊ณ  ์ค‘์ฒฉ์€ ๊ตฌ๋ฌธ์˜ ์•„ํ‹ฐํŒฉํŠธ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์„œ๋กœ์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ(์ด ๊ฒฝ์šฐ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•จ) ์ด๊ฒƒ์€ ์ˆœ์ฐจ ํ•จ์ˆ˜ ํ˜ธ์ถœ์—์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋ฉฐ ์ค‘์ฒฉ ์—†์ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด async/await ๊ฐ€ ๋งค๋ ฅ์ ์ธ ์ด์œ ์ž…๋‹ˆ๋‹ค. ๋‚ฎ์€ ์ˆ˜์ค€์˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์„ค๋ช…ํ•˜๋Š” ์ถ”๊ฐ€ ์ •๋ณด(Promise์˜ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„)๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋Œ€์‹  ๋†’์€ ์ˆ˜์ค€์˜ ์˜๋„(์‹œํ€€์Šค ์„ค๋ช…)์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๋Š” ๋ชฉ๋ก๋ณด๋‹ค ์œ ์—ฐํ•œ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ ๋ถ€๋ชจ์—๊ฒŒ ์ž์‹์ด ํ•˜๋‚˜๋งŒ ์žˆ์œผ๋ฉด ๋ณ‘์  ๋‚˜๋ฌด ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋ณธ์งˆ์ ์œผ๋กœ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค. Async/Await ๋ฐ Hooks๋Š” ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์— ๊ตฌ๋ฌธ์„ ๋‚ญ๋น„ํ•˜๊ณ  ์žˆ์Œ์„ ์ธ์‹ํ•˜๊ณ  ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ์ด์ „์— "์ด๊ฒƒ์€ ์ƒ์šฉ๊ตฌ์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ–ˆ๊ณ  ์ด์ œ๋Š” ๋‚ด ์ž์‹ ๊ณผ ๋ชจ์ˆœ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ์ž์ฒด๋กœ ๋นŒ๋”(๋˜๋Š” ์ตœ์†Œํ•œ React์˜ Render Props) ๋Š” "์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋…ผ๋ฆฌ" ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜(AFAIK)์ž…๋‹ˆ๋‹ค. ๋งŽ์ด ์‚ฌ์šฉํ•˜๋ฉด ์ธ์ฒด ๊ณตํ•™์ ์ด์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋™์ผํ•œ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ 4๊ฐœ ๋˜๋Š” 5๊ฐœ ์ด์ƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๋“ค์—ฌ์“ฐ๊ธฐ์— ์˜ํ•ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋‚™๋‹ดํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ๋‹ค์Œ ๋ ˆ๋ฒจ์€ ๊ฐ€๋…์„ฑ ํžˆํŠธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋‚˜์—๊ฒŒ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๋ถ€๋ถ„์€ ๋…์ž์˜ ์ค‘์ฒฉ ๋น„์šฉ์„ ์ค„์ด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ธ์ˆ˜๋Š” async / await ์™€ ์ •ํ™•ํžˆ ๊ฐ™์€ ์ธ์ˆ˜์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ์ฝ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  • ๊ณต๋ฐฑ์„ ๊ณผ๋„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์ž˜ ํ™•์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ชจ๋‹ˆํ„ฐ์— ๋„ˆ๋ฌด ๋งŽ์€ ๋ผ์ธ๋งŒ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ๊ฐ•์ œ ์Šคํฌ๋กค์€ ๊ฐ€๋…์„ฑ์„ ๊ฐ์†Œ์‹œํ‚ค๊ณ  congitive ๋ถ€ํ•˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ด๋ฏธ 60์ค„ ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ๋นŒ๋”๋ฅผ ์œ„ํ•ด ๋‚˜์—๊ฒŒ 15์ค„์„ ์ถ”๊ฐ€๋กœ ๊ฐ•์š”ํ–ˆ๋‹ค๊ณ  ์ƒ์ƒํ•ด๋ณด์‹ญ์‹œ์˜ค. ์ด์ƒ์ ์ด์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.
  • Hz ๊ณต๊ฐ„์„ ๋‚ญ๋น„ํ•˜๋ฉฐ, ์ด๋Š” ์ถ”๊ฐ€ ๋ž˜ํ•‘์œผ๋กœ ์ด์–ด์ง€๋ฉฐ ๋ผ์ธ ๊ณต๊ฐ„์„ ๋”์šฑ ๋‚ญ๋น„ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฝ˜ํ…์ธ ๋กœ ์•Œ๋ ค์ง„ ๋ฆฌํ”„ ๋…ธ๋“œ๋ฅผ ์™ผ์ชฝ์—์„œ ๋” ๋ฉ€๋ฆฌ, ํ•œ ๋ˆˆ์— ๋ณด๊ธฐ ํž˜๋“  ํŠธ๋ฆฌ ์•ˆ์œผ๋กœ ๋ฐ€์–ด ๋„ฃ์Šต๋‹ˆ๋‹ค.
  • 'ํ•ต์‹ฌ ํ”Œ๋ ˆ์ด์–ด' ๋˜๋Š” '๋น„์ƒ์šฉ์„ฑ'์„ ํ•œ ๋ˆˆ์— ์‹๋ณ„ํ•˜๋Š” ๊ฒƒ์€ ํ›จ์”ฌ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋‚ด ์ถ”๋ก ์ด ์‹œ์ž‘๋˜๊ธฐ ์ „์— "์ค‘์š”ํ•œ ๊ฒƒ์„ ์ฐพ์•„์•ผ" ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ๋ณด๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ๋น„ ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ๊ฐ•์กฐ ํ‘œ์‹œํ•˜๊ณ  ๋ˆˆ์ด ์‰ฝ๊ฒŒ ์ฆ๊ธธ ์ˆ˜ ์žˆ๋„๋ก ํ•จ๊ป˜ ๊ทธ๋ฃนํ™”๋˜์–ด ์žˆ๋Š”์ง€ ๋˜๋Š” ๋ˆˆ์ด ์ฃผ์œ„๋ฅผ ์Šค์บ”ํ•ด์•ผ ํ•˜๋Š” ๋ชจ๋“  ๊ณณ์— ํฉ์–ด์ ธ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฐ•์กฐ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐ•์กฐ ํ‘œ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งค์šฐ ์‰ฝ๊ฒŒ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ ์—†์ด๋Š” ๋ˆ„๊ฐ€ ๋ฌด์—‡์„ ์–ด๋””์—์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”์ง€ ํŒŒ์•…ํ•˜๊ธฐ ์ „์— ์ „์ฒด ์ƒ์„ธ ์ •๋ณด๋ฅผ ์ฝ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
image

์ด์ œ ์ด๊ฒƒ๊ณผ ๋น„๊ตํ•˜๋ฉด ๊ฐ•์กฐ ํ‘œ์‹œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ค‘๋ณต๋ฉ๋‹ˆ๋‹ค. ๋‚ด ๋ˆˆ์ด ๊ฐˆ ๊ณณ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
image

๊ฐ€๋…์„ฑ ๋Œ€ grokability์—์„œ ์•„๋งˆ๋„ ๋ถˆ์ผ์น˜๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์— ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. @Hixie ๋Š” ๋Œ€๊ทœ๋ชจ ํŠธ๋ฆฌ๋ฅผ ์ง€์†์ ์œผ๋กœ ์ฝ๊ณ  ์ดํ•ดํ•ด์•ผ ํ•˜๋Š” ๋ชจ๋†€๋ฆฌ์‹ ํด๋ž˜์Šค ํŒŒ์ผ์—์„œ ์‹œ๊ฐ„์„

์ฐธ๊ณ ๋กœ React์˜ Context๋Š” InheritedWidgets/Provider์ž…๋‹ˆ๋‹ค.

๊ทธ๋“ค ์‚ฌ์ด์˜ ์œ ์ผํ•œ ์ฐจ์ด์ ์€ ํ›„ํฌ ์ „์— React์—์„œ Builder ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ Context/Inheritedwidget์„ ์†Œ๋น„ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Flutter์—๋Š” ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๋‹ค์‹œ ๋นŒ๋“œ๋ฅผ ๋ฐ”์ธ๋”ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ InheritedWidgets๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠธ๋ฆฌ๋ฅผ ํ‰๋ฉดํ™”ํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋นŒ๋” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

Builder๊ฐ€ ๋œ ์ž์ฃผ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋…ผ์˜๊ฐ€ ๋” ์–ด๋ ค์šด ์ด์œ  ์ค‘ ํ•˜๋‚˜์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ํ›„ํฌ์™€ ๊ฐ™์€ ์†”๋ฃจ์…˜์„ ๋„์ž…ํ•˜๋ฉด https://github.com/flutter/flutter/issues/30062๋ฅผ ๋ชจ๋‘ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์–ธ๊ธ‰ํ•  ๊ฐ€์น˜๊ฐ€
๋ฐ https://github.com/flutter/flutter/issues/12992

๋˜ํ•œ @Hixie ๋Š” ๋‚ด ์˜๊ฒฌ์œผ๋กœ๋Š” ๋‹ค๋ฅธ ์–ธ์–ด๋ณด๋‹ค Flutter๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ํŠธ๋ฆฌ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊นŠ์€ ์ค‘์ฒฉ ํŠธ๋ฆฌ๋ฅผ ์ฝ๋Š” ๋ฐ ๋” ์ต์ˆ™ํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  Flutter ์ž์ฒด์˜ ์ฃผ์š” ๊ฐœ๋ฐœ์ž ์ค‘ ํ•œ ๋ช…์œผ๋กœ์„œ ๊ทธ๋Š” ํ›จ์”ฌ ๋” ๋งŽ์€ ๊ฒฝํ—˜์„ ํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Flutter๋Š” ๋ณธ์งˆ์ ์œผ๋กœ @Hixie ๊ฐ€ HTML5 ์‚ฌ์–‘์„ ๋งŒ๋“  ๊ฒฝํ—˜์ด ์žˆ๋Š” HTML๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊นŠ์€ ์ค‘์ฒฉ์ด ์žˆ๋Š” ์™ผ์ชฝ์—์„œ ์˜ค๋ฅธ์ชฝ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ฝ”๋“œ ๋ธ”๋ก์˜ ๊ฐ€์žฅ ์˜ค๋ฅธ์ชฝ ์ง€์ ์€ ์ฃผ์š” ๋…ผ๋ฆฌ์™€ ๋ฐ˜ํ™˜ ๊ฐ’์ด ์žˆ๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, ๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž๋Š” ๊ทธ๋ ‡์ง€ ์•Š๋‹ค, ๋˜๋Š” ํ•˜๋‹จ ์–ธ์–ด์— ๋”

๊ทธ๊ฒƒ์„ ๋ณด๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ๋‚ด ๋‘๋‡Œ๊ฐ€ ์‹œ๊ฐ์ ์œผ๋กœ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ์ฝ”๋“œ์˜ ์–‘์ž…๋‹ˆ๋‹ค. ๋‚˜์—๊ฒŒ ์ด๊ฒƒ์€ ํŠธ๋ฆฌ์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” ๋‚ด์šฉ์„ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ธฐ ์ „์— ๋‚ด ๋‘๋‡Œ๊ฐ€ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” "๊ฐ„๋‹จํ•œ ์ž‘์—…"์„ ์ •ํ™•ํ•˜๊ฒŒ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
image

๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ ๋นŒ๋” ๋ฒ„์ „์€ ๋ง ๊ทธ๋Œ€๋กœ ์ถ”๊ฐ€ ์ •๋ณด๋‚˜ ์ปจํ…์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์œผ๋ฉด์„œ 4๋ฐฐ ๋” ํฐ ์ˆ˜์ง ๊ณต๊ฐ„์„ ๊ฐ€์ง€๋ฉฐ ํ›จ์”ฌ ๋” ํฌ์†Œ/์‚ฐ๋ž€ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์••์ถ•ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์ƒ๊ฐ์— ๊ทธ๊ฒƒ์€ ์—ด๋ ค ์žˆ๊ณ  ๋‹ซํžŒ ๊ฒฝ์šฐ์ด๋ฉฐ, ๊ทธ ์ด์œ ๋งŒ์œผ๋กœ ๊ฐ๊ด€์ ์œผ๋กœ ์ฝ๊ธฐ๊ฐ€ ์‰ฝ์ง€ ์•Š์œผ๋ฉฐ, ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ํ”Œ๋Ÿฌํ„ฐ๋กœ ์ฒ˜๋ฆฌํ•œ ๋“ค์—ฌ์“ฐ๊ธฐ ๋ฐ ์ค‘๊ด„ํ˜ธ ์ •๋ ฌ์— ๋Œ€ํ•œ ์ถ”๊ฐ€์ธ์ง€ ๋ถ€ํ•˜๋ฅผ ๊ณ ๋ คํ•˜์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚ด ๋ˆˆ์„ ์ฒ˜๋ฆฌ์— ๋” ์ตœ์ ํ™”๋œ ๋ฐฐ๊ณ ํ”ˆ CPU๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ? :)

์ผ๋ฐ˜์ ์ธ View -> Text ์ค‘์ฒฉ ๋“ฑ์˜ ๊ฒฝ์šฐ ์ค‘์ฒฉ์€ ํ™”๋ฉด์— _๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„_๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. Context์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์˜ ๊ฒฝ์šฐ(Flutter์— ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Œ) ์ปจํ…์ŠคํŠธ์˜ ๋ฒ”์œ„๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ค‘์ฒฉ ์ž์ฒด๋Š” ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์— ์ค‘์š”ํ•œ ์˜๋ฏธ๋ก ์  ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๋ฉฐ ๋ฌด์‹œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ถ€๋ชจ์™€ ์ž์‹์˜ ์ž๋ฆฌ๋งŒ ๋ฐ”๊ฟ”์„œ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™์„ ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์ „์ ์œผ๋กœ ๋™์˜ํ•˜๋ฉฐ ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ƒํƒœ๊ฐ€ ์žˆ๋Š” ์ถ”๊ฐ€ ๋น„์‹œ๊ฐ์  ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ์  ๋””์Šคํ”Œ๋ ˆ์ด ํŠธ๋ฆฌ์— ์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ ๋ ˆ์ด์–ด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ์˜๋ฏธ์ƒ ์˜๋ฏธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. 5๊ฐœ์˜ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด์ œ ์œ„์ ฏ์˜ ๊นŠ์ด๊ฐ€ 5๊ฐœ์ž…๋‹ˆ๊นŒ? ๊ทธ ๋†’์€ ์ˆ˜์ค€์—์„œ๋งŒ ํ˜„์žฌ ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋ƒ„์ƒˆ๊ฐ€๋‚ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ๋‘ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๊ฐ’๋น„์‹ผ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์–ผ๋งˆ๋‚˜ ์–ด๋ ต๊ณ  ๋ช…์‹œ์ ์ด์–ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์˜๊ฒฌ์ด ๋ถ„๋ถ„ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Flutter์˜ ์ฒ ํ•™์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์–ธ์ œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ• ์ง€์— ๋Œ€ํ•ด ์ง„์ง€ํ•˜๊ฒŒ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋„๋ก ๋” ์–ด๋ ต๊ณ  ๋ช…์‹œ์ ์ด์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ŠคํŠธ๋ฆผ, ์• ๋‹ˆ๋ฉ”์ด์…˜, ๋ ˆ์ด์•„์›ƒ ๋นŒ๋” ๋“ฑ์€ ๋„ˆ๋ฌด ์‰ฌ์šธ ๊ฒฝ์šฐ ๋น„ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์‚ฌ์†Œํ•˜์ง€ ์•Š์€ ๋น„์šฉ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

  2. ๋นŒ๋“œ๋Š” ๋™๊ธฐํ™”์ด์ง€๋งŒ ์•ฑ ๊ฐœ๋ฐœ์ž๋กœ์„œ ๋‹ค๋ฃจ๋Š” ๊ฐ€์žฅ ํฅ๋ฏธ๋กœ์šด ๊ฒƒ์€ ๋น„๋™๊ธฐ์ž…๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๋นŒ๋“œ๋ฅผ ๋น„๋™๊ธฐ์‹์œผ๋กœ ๋งŒ๋“ค ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” Stream/Animation/FutureBuilder์™€ ๊ฐ™์€ ์ด๋Ÿฌํ•œ ํŽธ์˜๋ฅผ ๋งŒ๋“ค์—ˆ์ง€๋งŒ ๊ฐœ๋ฐœ์ž๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฒƒ์— ํ•ญ์ƒ ์ถฉ๋ถ„ํžˆ ์ž˜ ์ž‘๋™ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ Stream์ด๋‚˜ FutureBuilder๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฌผ๋ก  ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๋น„๋™๊ธฐ ์ž‘์—…์œผ๋กœ ์ž‘์—…ํ•  ๋•Œ ํ•ญ์ƒ ์‚ฌ์šฉ์ž ์ง€์ • ๋ Œ๋” ๊ฐœ์ฒด๋ฅผ ์ž‘์„ฑํ•˜๋„๋ก ์ง€์‹œํ•˜๋Š” ๊ฒƒ์ด ์†”๋ฃจ์…˜์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฒ„๊ทธ์—์„œ ๋‚ด๊ฐ€ ๋ณด๊ณ  ์žˆ๋Š” ์˜ˆ์—๋Š” ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๋ƒฅ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์—†๋Š” ๋น„๋™๊ธฐ ๋ฐ ๋™๊ธฐํ™” ์ž‘์—…์ด ํ˜ผํ•ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œ๋Š” ๋ชจ๋“  ํ˜ธ์ถœ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

fwiw์—์„œ React ํŒ€์€ 1 ๋™๊ธฐ๋กœ ๊ฐ€๋…์„ฑ ๋ฌธ์ œ ์žฌ์‚ฌ์šฉ์„ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.
Hooks Motivation: ์ปดํฌ๋„ŒํŠธ ๊ฐ„์— Stateful ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
React ๋Š” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋™์ž‘์„ ๊ตฌ์„ฑ ์š”์†Œ์— "์ฒจ๋ถ€"ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค . ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ํŒจํ„ด์— ์ต์ˆ™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์žฌ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฒˆ๊ฑฐ๋กญ๊ณ  ์ฝ”๋“œ๋ฅผ ๋”ฐ๋ฅด๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค .

์ด๊ฒƒ์€ Flutter๊ฐ€ ํ˜„์žฌ ๊ธฐ๋ณธ์ ์œผ๋กœ '์ƒํƒœ๋ฅผ ๊ตฌ์„ฑ'ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ ˆ์ด์•„์›ƒ ํŠธ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ์ž‘์—…ํ•˜๊ธฐ๊ฐ€ ๋” ๋ณต์žกํ•˜๊ณ  "๋”ฐ๋ผํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์›Œ์ง€๋Š”" ๋นŒ๋”๋ฅผ ๋งŒ๋“ค ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์ผ์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.

build ๊ฐ€ ๋งค๋ฒˆ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ @dnfield ์•„๋งˆ๋„ ๋นŒ๋“œ๊ฐ€ ํ•ญ์ƒ ๋™๊ธฐํ™”๋˜๋„๋ก build ๋ฉ”์„œ๋“œ์— ์—†๋Š” ํ›„ํฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค initState ๋ฐ dispose ์ž…๋‹ˆ๋‹ค. ํ›„ํฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์‚ฌ๋žŒ๋“ค๋กœ๋ถ€ํ„ฐ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

Promises/Futures์— ๋Œ€ํ•ด ๋™์ผํ•œ ์ฃผ์žฅ์„ ํ•˜๊ณ  await ๊ฐ€ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ชจํ˜ธํ•˜๊ฒŒ ํ•œ๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋‹ˆ์š”. Await๋Š” ๋ง ๊ทธ๋Œ€๋กœ ํ•˜๋‚˜์˜ ๋‹จ์ผ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๊ตฌ๋ฌธ ์„คํƒ•์ž…๋‹ˆ๋‹ค. ์žฅํ™ฉํ•œ Futures ๋˜๋Š” ์„ ์–ธ์  ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋‚ ์”จ์— ์ฝ”๋“œ์˜ __intent__๋Š” ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋™์ผํ•œ ์šฐ์‚ฐ ์•„๋ž˜๋กœ ์˜ฎ๊ธฐ๊ณ , ๋‹จ์ผ ํ‚ค์›Œ๋“œ ๋’ค์— ๋ชจ๋“  ์ข…๋ฅ˜์˜ ๋‹ค๋ฅธ ๋™์ž‘์„ ์ˆจ๊ธฐ๊ณ , ์–ด๋–ป๊ฒŒ๋“  ์ธ์ง€ ๋ถ€ํ•˜๋ฅผ ์ค„์ธ๋‹ค๊ณ  ์ฃผ์žฅํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ์™„์ „ํžˆ ์ž˜๋ชป๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ œ ๊ทธ ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ๊ฒฐ๊ณผ๊ฐ€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๋ถˆํ•„์š”ํ•œ ์žฌ๊ตฌ์ถ•์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๊ณ , ์ˆ˜๋ช…์ด ๊ธด ๊ฐœ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ , ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๋””์Šคํฌ์—์„œ ํŒŒ์ผ์„ ์ฝ๊ฑฐ๋‚˜, ๋‹จ์ˆœํžˆ ์ •์  ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ๊ถ๊ธˆํ•ดํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. . ์ด ๋ชจ๋“  ์ƒํ™ฉ์€ ๋งค์šฐ ๋‹ค๋ฅด๋ฉฐ ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ํ›„ํฌ์˜ ๋ง›์— ์ต์ˆ™ํ•ด์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ ์žˆ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž๋Š” ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š” ์—†์ด ์ด๋Ÿฌํ•œ "ํ›„ํฌ"๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ์„ธ๋ถ€ ์‚ฌํ•ญ์— ์‹ ๊ฒฝ์“ฐ๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜์ง€ ์•Š๊ณ  ์†์‰ฌ์šด ๊ฐœ๋ฐœ์„ ์›ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ํ† ๋ก ์—์„œ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.
์™„์ „ํ•œ ์˜๋ฏธ๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์ฑ„ ์†Œ์œ„ "ํ›„ํฌ"๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋น„ํšจ์œจ์ ์ด๊ณ  ์ž˜๋ชป๋œ ์ฝ”๋“œ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์‚ฌ๋žŒ๋“ค์ด ๋ฐœ์— ์ด์„ ์˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ "์ดˆ๋ณด์ž ๊ฐœ๋ฐœ์ž ๋ณดํ˜ธ" ๋ฌธ์ œ๋„ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ๊ฐ„๋‹จํ•˜๋‹ค๋ฉด ํ›„ํฌ๋ฅผ ๊ธฐ๊บผ์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋นŒ๋”๋ฅผ ์›ํ•˜๋Š” ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์ค‘์ฒฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์•ฑ์ด ๋ณต์žกํ•ด์ ธ์„œ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์„ ๊ฒช์„์ˆ˜๋ก ์ž์‹ ์˜ ์ฝ”๋“œ์™€ ์•„ํ‚คํ…์ฒ˜์— ๋” ๋งŽ์€ ๊ด€์‹ฌ์„ ๊ธฐ์šธ์—ฌ์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ž ์žฌ์ ์œผ๋กœ ์ˆ˜๋ฐฑ๋งŒ ๋ช…์˜ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ์•ฑ์„ ๊ตฌ์ถ•ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์ค‘์š”ํ•œ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ์ถ”์ƒํ™”ํ•˜๋Š” "๋งˆ๋ฒ•"์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋งค์šฐ ์ฃผ์ €ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ ์ €๋Š” Flutter์˜ API๊ฐ€ ๋งค์šฐ ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ๋‹จ์ˆœํ•˜๊ณ , ๋ˆ„๊ตฌ๋‚˜ ๋งค์šฐ ํšจ์œจ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๋ชจ๋“  ์ข…๋ฅ˜์˜ ๋ณต์žกํ•œ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ฌ์ „ํžˆ ์œ ์—ฐํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค.

@Rudiksz ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ์•„๋ฌด๋„ ํ›„ํฌ๋กœ ์ด๋™ํ•˜๋„๋ก ๊ฐ•์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ์Šคํƒ€์ผ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์ด ์ง€์‹์— ์ง๋ฉดํ•˜์—ฌ ๋‹น์‹ ์˜ ์ฃผ์žฅ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์–ด์จŒ๋“  ์‚ฌ๋žŒ๋“ค์€ ์—ฌ๋Ÿฌ ํ›„ํฌ๊ฐ€ ์–ด๋–ป๊ฒŒ๋“  ์•ฑ์„ ์ฐจ๋‹จํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜๋ฉด ์—ฌ์ „ํžˆ ํšจ์œจ์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ์Šคํƒ€์ผ์—์„œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ”„๋กœํ•„์„ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์•ฑ์„ ์‹คํ–‰ํ•  ๋•Œ๋„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Rudiksz ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ์•„๋ฌด๋„ ํ›„ํฌ๋กœ ์ด๋™ํ•˜๋„๋ก ๊ฐ•์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ์Šคํƒ€์ผ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์ด ์ง€์‹์— ์ง๋ฉดํ•˜์—ฌ ๋‹น์‹ ์˜ ์ฃผ์žฅ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ด๋Ÿฐ, ์ด ๊ฐ™์€ ์ฃผ์žฅ์€ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋ถˆํ‰ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋„ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์•„๋ฌด๋„ ํ›„ํฌ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ๊ฐ•์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์—ฌ๊ธฐ์„œ ๋งค์šฐ ๋ฌด๋š๋šํ•  ๊ฒƒ์ด๋‹ค.
์ด ๋ฌธ์ œ๋Š” ์‹ค์ œ๋กœ ํ›„ํฌ, statefulwidget ๋ฐ ๋ˆ„๊ฐ€ ๋ฌด์—‡์„ ์‚ฌ์šฉํ•˜๋Š”์ง€์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์ด 5์ค„์˜ ์ฝ”๋“œ๋ฅผ ๋œ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์‹ญ ๋…„์˜ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋˜๋Œ๋ฆฌ๋Š” ๊ฒƒ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‹น์‹ ์˜ ์ฃผ์žฅ์€ ์ •๋ง ํ†ตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ ์ƒ์„ฑ๋œ ์ด์œ ๋Š” flutter_hooks ํŒจํ‚ค์ง€๊ฐ€ ํ”„๋ ˆ์ž„์›Œํฌ์— ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š” ๋ฐ˜๋ฉด ํ˜„์žฌ ๋ชจ๋ธ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋ ˆ์ž„์›Œํฌ์— ์ด๋ฏธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ธ์ˆ˜๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ flutter_hooks์˜ ๊ธฐ๋Šฅ์„ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์˜ ์ฃผ์žฅ์€ ๋‚ด๊ฐ€ ํ˜„์žฌ ๋ชจ๋ธ๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๋ฌด์—‡์ด๋“ ์ง€ ํ›„ํฌ ํŒจํ‚ค์ง€๋กœ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์‹ค์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ด ํ† ๋ก ์˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์‚ฌ์‹ค์ด๋ผ๋ฉด ์ž‘๋™ํ•  ๊ฒƒ์ด๊ณ , ์ด๋Š” ๋˜ํ•œ ํ›„ํฌ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋ ˆ์ž„์›Œํฌ์— ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋ฉฐ, ๋”ฐ๋ผ์„œ ๋‹ค์‹œ ํ›„ํฌ์™€ ๋น„ํ›„ํฌ๊ฐ€ ๋™์ผํ•˜๋ฏ€๋กœ ํ˜„์žฌ ๋ชจ๋ธ๊ณผ ํ›„ํฌ ๊ธฐ๋ฐ˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๊ฐ€ ์ฃผ์žฅํ–ˆ๋˜ ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๋ชจ๋ฒ” ์‚ฌ๋ก€์ด๊ณ  ๊ณผ๋„ํ•œ ์ค‘์ฒฉ์ด ์•ˆํ‹ฐ ํŒจํ„ด์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋ชจ๋ฒ” ์‚ฌ๋ก€๊ฐ€ ์–ด๋””์—์„œ ์™”๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ •ํ™•ํžˆ ์–ด๋–ค ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์–ธ๊ธ‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

fwiw์—์„œ React ํŒ€์€ 1 ๋™๊ธฐ๋กœ ๊ฐ€๋…์„ฑ ๋ฌธ์ œ ์žฌ์‚ฌ์šฉ์„ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.
Hooks Motivation: ์ปดํฌ๋„ŒํŠธ ๊ฐ„์— Stateful ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
React ๋Š” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋™์ž‘์„ ๊ตฌ์„ฑ ์š”์†Œ์— "์ฒจ๋ถ€"ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค . ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ํŒจํ„ด์— ์ต์ˆ™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์žฌ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฒˆ๊ฑฐ๋กญ๊ณ  ์ฝ”๋“œ๋ฅผ ๋”ฐ๋ฅด๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค .

Flutter๊ฐ€ React๋ณด๋‹ค ํ›จ์”ฌ ๋” ํ›Œ๋ฅญํ•˜๋‹ค๊ณ  ๋ชจ๋“  ์‚ฌ๋žŒ๋“ค์ด ์—ด๊ด‘ํ•˜๋Š” ๊ฒƒ์„ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. React๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ผ์„ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ผ๊นŒ์š”? Flutter๊ฐ€ React๋ณด๋‹ค ๋ช‡ ๋งˆ์ผ ์•ž์„œ ์žˆ๋‹ค๊ณ  ๋งํ•  ์ˆ˜๋„ ์—†๊ณ  ๋ชจ๋“  ์ž‘์—…์„ React์™€ ๋˜‘๊ฐ™์ด ์ˆ˜ํ–‰ํ•˜๋„๋ก ์š”์ฒญํ•  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค.

Flutter๊ฐ€ ์ฃผ์–ด์ง„ ๋ฌธ์ œ์— ๋Œ€ํ•ด ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•œ ์†”๋ฃจ์…˜์€ ๋ฌด์—‡์ด๋“  ์ž์ฒด ์žฅ์ ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” React์— ์ต์ˆ™ํ•˜์ง€ ์•Š์ง€๋งŒ ๋ถ„๋ช…ํžˆ ๋‚˜๋Š” โ€‹โ€‹์ •๋ง ๋†€๋ผ์šด ๊ธฐ์ˆ ์„ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. :/

Flutter๊ฐ€ React์™€ ๊ฐ™์€ ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ฃผ์žฅํ•˜๋Š” ์‚ฌ๋žŒ์€ ์•„๋ฌด๋„ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์‹ค Flutter์˜ ์œ„์ ฏ ๋ ˆ์ด์–ด๋Š” React์—์„œ ํฌ๊ฒŒ ์˜๊ฐ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค. ๊ณต์‹ ๋ฌธ์„œ์— ๋‚˜์™€ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ฒฐ๊ณผ์ ์œผ๋กœ ์œ„์ ฏ์€ React ๊ตฌ์„ฑ ์š”์†Œ์™€ ๋™์ผํ•œ ์ด์ ๊ณผ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋˜ํ•œ React๊ฐ€ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ฐ Flutter๋ณด๋‹ค ๋” ๋งŽ์€ ๊ฒฝํ—˜์„ ๊ฐ€์ง€๊ณ  ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ์€ ๊ทธ๋“ค์„ ๋” ์˜ค๋ž˜ ๋งˆ์ฃผํ–ˆ๊ณ  ๋” ์ž˜ ์ดํ•ดํ–ˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ Flutter ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด React ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜๊ณผ ์œ ์‚ฌํ•˜๋‹ค๋Š” ๊ฒƒ์€ ๋†€๋ผ์šด ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค.

@Rudiksz Flutter์˜ ์‚ฌ์šฉ์ž API๋Š” ๋‚ด๋ถ€ API๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  React์˜ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ๋ชจ๋ธ๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ํ›„ํฌ์™€ ์œ ์‚ฌํ•œ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๊ฑฐ์˜ ๋…์ ์ ์œผ๋กœ ๊ธฐ๋ฐ˜์„ ๋‘” ์˜๊ฒฌ์˜ ์ด๋ถ„๋ฒ•์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ํ›„ํฌ๊ฐ€ ์žˆ๋Š” React๋ฅผ ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์œ ์‚ฌ์„ฑ์„ ๊ฐ์•ˆํ•  ๋•Œ, ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด ์œ ์‚ฌํ•ด ๋ณด์ด๋Š” ๊ฒƒ์€ ๋†€๋ผ์šด ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค.

์ œ๋ฐœ ์„œ๋กœ ์‹ธ์šฐ์ง€ ์•Š๋„๋ก ์ตœ์„ ์„ ๋‹คํ•ฉ์‹œ๋‹ค.

์‹ธ์›€์ด ์šฐ๋ฆฌ๋ฅผ ์ด๋Œ ์œ ์ผํ•œ ๊ฒƒ์€ ์ด ํ† ๋ก ์„ ๋๋‚ด๊ณ  ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค.

Flutter๊ฐ€ React๋ณด๋‹ค ํ›จ์”ฌ ๋” ํ›Œ๋ฅญํ•˜๋‹ค๊ณ  ๋ชจ๋“  ์‚ฌ๋žŒ๋“ค์ด ์—ด๊ด‘ํ•˜๋Š” ๊ฒƒ์„ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. React๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ผ์„ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ผ๊นŒ์š”? Flutter๊ฐ€ React๋ณด๋‹ค ๋ช‡ ๋งˆ์ผ ์•ž์„œ ์žˆ๋‹ค๊ณ  ๋งํ•  ์ˆ˜๋„ ์—†๊ณ  ๋ชจ๋“  ์ž‘์—…์„ React์™€ ๋˜‘๊ฐ™์ด ์ˆ˜ํ–‰ํ•˜๋„๋ก ์š”์ฒญํ•  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค.

React ํŒ€์ด ํ›„ํฌ๋ฅผ ์ƒ๊ฐํ•ด ๋ƒˆ์„ ๋•Œ ๋น„์Šทํ•œ ๋™๊ธฐ๊ฐ€ ์žˆ์—ˆ๋‹ค๋Š” ์ ์„ ์ง€์ ํ•˜๋ฉด์„œ ์—ฌ๊ธฐ์—์„œ ํ‘œํ˜„ํ•˜๋Š” ์šฐ๋ ค๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ด ์œ ํ˜•์˜ ๊ตฌ์„ฑ ์š”์†Œ ๊ธฐ๋ฐ˜ ํ”„๋ ˆ์ž„์›Œํฌ ๋‚ด์—์„œ ๊ณตํ†ต ์ƒํƒœ ์ €์žฅ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ณ  ๊ฒฐํ•ฉํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Œ์„ ํ™•์‹คํžˆ ํ™•์ธํ•˜๊ณ  ๊ฐ€๋…์„ฑ, ์ค‘์ฒฉ ๋ฐ ๋ณด๊ธฐ์˜ "ํด๋Ÿฌํ„ฐ"์— ๋Œ€ํ•œ ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋…ผ์˜๋ฅผ ์–ด๋Š ์ •๋„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ค ๊ฒƒ์— ๋Œ€ํ•ด์„œ๋„ ์—ด๊ด‘ํ•˜์ง€ ์•Š๊ณ  React์—์„œ ์ผํ•œ ์ ๋„ ์—†๊ณ  Flutter๋ฅผ ์‚ฌ๋ž‘ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋ฅผ ์‰ฝ๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Rudiksz ์‹ค์ œ๋กœ ์ ์šฉํ•  ๋•Œ๊นŒ์ง€ ์‹ค์ œ๋กœ ์„ฑ๋Šฅ์ด

@Hixie ์ด๊ฒƒ์€ HookWidget ๋ฐ StatefulWidget ๋‘˜ ๋‹ค๋กœ userId์˜ ์‚ฌ์šฉ์ž ๋‹‰๋„ค์ž„์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•œ ์œ„์ ฏ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ผ๋ฐ˜ ํ”Œ๋Ÿฌํ„ฐ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ์—ฌ์ •์˜ ์˜ˆ์ž…๋‹ˆ๋‹ค.

__ํ›„ํฌ ์œ„์ ฏ__

String useUserNickname(Id userid) {
  final name = useState("");
  useEffect(async () {
    name.value = "Loading...";
    name.value = await fetchNicknames()[userId;
  }, [userId]);
  return name.value;
}

class UserNickname extends HookWidget {

  final userId;

  Widget build(BuildContext context) {
    final nickname = useUserNickname(userId);
    return Text(nickname);
  }
}

__์ƒํƒœ ์ €์žฅ ์œ„์ ฏ__

class UserNickname extends Widget {
  final userId;
  // ... createState() ...
}

class UserNicknameState extends State {

  String nickname= "";

   initState() {
     super.initState();
     fetchAndUpdate();
   }

   fetchAndUpdate() async {
      setState(() { this.nickname = "Loading..." });
      final result = await fetchNicknames()[widget.userId];
      setState(() { this.nickname = result });
    }


 void didUpdateWidget(oldWidget) { 
     if (oldWidget.userId != widget.userId) {
        fetchAndUpdate();
     }
   }

  Widget build(BuildContext context) {
    return Text(this.nickname);
  }
}

์ง€๊ธˆ๊นŒ์ง€ ํฅ๋ฏธ๋กœ์šด ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. ๋‘ ์†”๋ฃจ์…˜ ๋ชจ๋‘ ์ƒ๋‹นํžˆ ์ˆ˜์šฉ ๊ฐ€๋Šฅํ•˜๊ณ  ๊ฐ„๋‹จํ•˜๋ฉฐ ์„ฑ๋Šฅ์ด ๋›ฐ์–ด๋‚ฉ๋‹ˆ๋‹ค.
์ด์ œ UserNickname ๋‚ด๋ถ€์—์„œ ListView UserNickname ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋ณด์‹œ๋‹ค์‹œํ”ผ fetchNicknames๋Š” ํ•˜๋‚˜์˜ ๋‹‰๋„ค์ž„๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹‰๋„ค์ž„์˜ ๋งต์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋งค๋ฒˆ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ๋ถˆํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์†”๋ฃจ์…˜:

  • fetchNicknames() ํ˜ธ์ถœ ๋กœ์ง์„ ์ƒ์œ„ ์œ„์ ฏ์œผ๋กœ ์ด๋™ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ์บ์‹œ ๊ด€๋ฆฌ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์†”๋ฃจ์…˜์€ ํ—ˆ์šฉ๋˜์ง€๋งŒ 2๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
1 - ์ด์ œ UserNickname ์“ธ๋ชจ์—†๊ฒŒ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์ด๊ฒƒ์€ ์ด์ œ ๋‹จ์ง€ ํ…์ŠคํŠธ ์œ„์ ฏ์ด๊ณ  ๋‹ค๋ฅธ ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ƒ์œ„ ์œ„์ ฏ( ListView )์—์„œ ์ˆ˜ํ–‰ํ•œ ์ž‘์—…์„ ๋ฐ˜๋ณตํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. . ๋‹‰๋„ค์ž„์„ ๋ณด์—ฌ์ฃผ๋Š” ๋กœ์ง์€ UserNickname ํ•˜์ง€๋งŒ ๋”ฐ๋กœ โ€‹โ€‹์˜ฎ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
2 - ๋‹ค๋ฅธ ๋งŽ์€ ํ•˜์œ„ ํŠธ๋ฆฌ์—์„œ fetchNicknames() ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ํ•œ ๋ถ€๋ถ„๋งŒ์ด ์•„๋‹ˆ๋ผ ๋ชจ๋“  ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ๋Œ€ํ•ด ์บ์‹œํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์บ์‹œ ๊ด€๋ฆฌ์ž๋ฅผ ์„ ํƒํ•˜๊ณ  InheritedWidgets ๋˜๋Š” Provider ์žˆ๋Š” CacheManager ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค๊ณ  ์ƒ์ƒํ•ด ๋ณด์‹ญ์‹œ์˜ค.

์บ์‹ฑ์— ๋Œ€ํ•œ ์ง€์›์„ ์ถ”๊ฐ€ํ•œ ํ›„:

__ํ›„ํฌ ์œ„์ ฏ__

String useUserNickname(Id userid) {
  final context = useContext();
  final cache = Provider.of<CacheManager>(context);
  final name = useState("");
  useEffect(async () {
    name.value = "Loading...";
    var cachedValue = cache.get("nicknames");
    if (cachedValue == null || cachedValue[widget.userId] == null) {
        final result = await fetchNicknames();
        cache.set("nicknames", result );
        cachedValue = result ;
    }
    final result = cachedValue[widget.userId];
    name.value = result ;
  }, [userId]);
  return name.value;
}

class UserNickname extends HookWidget {

  final userId;

  Widget build(BuildContext context) {
    final nickname = useUserNickname(userId);
    return Text(nickname);
  }
}

__์ƒํƒœ ์ €์žฅ ์œ„์ ฏ__

class UserNickname extends Widget {
  final userId;
  // ... createState() ...
}

class UserNicknameState extends State {

  String nickname= "";
  CacheManager cache;

   initState() {
     super.initState();
     fetchAndUpdate();
     this.cache = Provider.of<CacheManager>(context);
   }

   fetchAndUpdate() async {
      setState(() { this.nickname = "Loading..." });
      var cachedValue = this.cache.get("nicknames");
      if (cachedValue == null || cachedValue[widget.userId] == null) {
        final result = await fetchNicknames();
        this.cache.set("nicknames", result );
        cachedValue = result ;
      }
      final result = cachedValue [widget.userId];
      setState(() { this.nickname = result });
    }


 void didUpdateWidget(oldWidget) { 
     if (oldWidget.userId != widget.userId) {
        fetchAndUpdate();
     }
   }

  Widget build(BuildContext context) {
    return Text(this.nickname);
  }
}

๋ณ„๋ช…์ด ๋ณ€๊ฒฝ๋  ๋•Œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์•Œ๋ฆฌ๋Š” ์†Œ์ผ“ ์„œ๋ฒ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

__ํ›„ํฌ ์œ„์ ฏ__

String useUserNickname(Id userid) {
  final context = useContext();
  final cache = Provider.of<CacheManager>(context);
  final notifications = Provider.of<ServiceNotifications>(context);
  final name = useState("");

  fetchData() async {
    name.value = "Loading...";
    var cachedValue = cache.get("nicknames");
    if (cachedValue == null || cachedValue[widget.userId] == null) {
        final result = await fetchNicknames();
        cache.set("nicknames", result );
        cachedValue = result ;
    }
    final result = cachedValue[widget.userId];
    name.value = result ;
   }

  useEffect(() {
     final sub = notifications.on("nicknameChanges", fetchData);
     return () => sub.unsubscribe();
   }, [])

  useEffect(fetchData, [userId]);
  return name.value;
}

class UserNickname extends HookWidget {

  final userId;

  Widget build(BuildContext context) {
    final nickname = useUserNickname(userId);
    return Text(nickname);
  }
}

__์ƒํƒœ ์ €์žฅ ์œ„์ ฏ__

class UserNickname extends Widget {
  final userId;
  // ... createState() ...
}

class UserNicknameState extends State {

  String nickname= "";
  CacheManager cache;
  ServerNotification notifications;
  CancelableOperation sub;

   initState() {
     super.initState();
     fetchAndUpdate();
     this.cache = Provider.of<CacheManager>(context);
     this.notifications = Provider.of<ServerNotification>(context);
     this.sub = notifications.on("nicknameChanges", fetchAndUpdate);
   }

   dispose() {
      super.dispose();
      this.sub.unsubscribe();
   }

   fetchAndUpdate() async {
      setState(() { this.nickname = "Loading..." });
      var cachedValue = this.cache.get("nicknames");
      if (cachedValue == null || cachedValue[widget.userId] == null) {
        final result = await fetchNicknames();
        this.cache.set("nicknames", result );
        cachedValue = result ;
      }
      final result = cachedValue [widget.userId];
      setState(() { this.nickname = result });
    }


 void didUpdateWidget(oldWidget) { 
     if (oldWidget.userId != widget.userId) {
        fetchAndUpdate();
     }
   }

  Widget build(BuildContext context) {
    return Text(this.nickname);
  }
}

์ง€๊ธˆ๊นŒ์ง€ ๊ตฌํ˜„์€ ๋ชจ๋‘ ์ˆ˜์šฉ ๊ฐ€๋Šฅํ•˜๊ณ  ์ข‹์Šต๋‹ˆ๋‹ค. IMO statful์˜ ์ƒ์šฉ๊ตฌ๋Š” ์ „ํ˜€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž์˜ ๋‹‰๋„ค์ž„๊ณผ ์•„๋ฐ”ํƒ€๊ฐ€ ๋ชจ๋‘ ์žˆ๋Š” UserInfo ์™€ ๊ฐ™์€ ์œ„์ ฏ์ด ํ•„์š”ํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ "Welcome [username]"๊ณผ ๊ฐ™์€ ๋ฌธ์žฅ์œผ๋กœ ํ‘œ์‹œํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— UserNickname ์œ„์ ฏ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

__ํ›„ํฌ ์œ„์ ฏ__

useFetchUserNickname(userId) // old code
useUserAvatar(userId) // implementation like `useFetchUserNickname`

class UserNickname extends HookWidget {
  final userId;

  Widget build(BuildContext context) {
    final nickname = useUserNickname(userId);
    final avatar = useUserAvatar(userId);
    return Row(
      children: [Image.network(avatar), Text(nickname)],
    );
  }
}

ํ•˜์ง€๋งŒ __stateful ์œ„์ ฏ__์˜ ๊ฒฝ์šฐ ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ๋กœ์ง์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋กœ์ง์„ ํด๋ž˜์Šค๋กœ ์ด๋™ํ•ด์•ผ ํ•˜๋ฉฐ(์˜ˆ: Property ) ์—ฌ์ „ํžˆ ์ƒˆ ์œ„์ ฏ์—์„œ ์†์„ฑ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์œ„์ ฏ ๊ธ€๋ฃจ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ 3๊ฐœ์˜ ์˜ˆ์—์„œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ณด๋ฉด ์œ„์ ฏ ์ž์ฒด๋ฅผ ์ „ํ˜€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ์ƒํƒœ ๋…ผ๋ฆฌ์—๋งŒ ์žˆ๊ณ  ๋ณ€๊ฒฝ๋œ ์œ ์ผํ•œ ์œ„์น˜๋Š” ๋ชจ๋‘ ์ƒํƒœ ๋…ผ๋ฆฌ์˜€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ์šฐ๋ฆฌ์—๊ฒŒ ์–ด๋””์—์„œ๋‚˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊นจ๋—ํ•˜๊ณ (์˜๊ฒฌ์ด ์žˆ๋Š”) ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•˜๊ณ  ์™„์ „ํžˆ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ์ œ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.

IMHO์˜ ์œ ์ผํ•œ ๋ฌธ์ œ๋Š” useUserNickname ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ๋‹จ์ผ ํ•จ์ˆ˜๊ฐ€ ์ด๋งŒํผ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฌด์„ญ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ๋ฐ˜์‘์— ๋Œ€ํ•œ ๊ฒฝํ—˜๊ณผ ํ”„๋กœ๋•์…˜ rn(ํ›„ํฌ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š”)์— ์žˆ๋Š” 2๊ฐœ์˜ ์•ฑ์—์„œ flutter_hooks ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝํ—˜์€ ์ข‹์€ ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ์—†์Œ์„ ์ฆ๋ช…ํ•ฉ๋‹ˆ๋‹ค(์ €๋„ MobX ๋ฐ ๊ธฐํƒ€ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์œ„์ ฏ์˜ ์ ‘์ฐฉ์ œ๋Š” ํ•ญ์ƒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค)๊ฐ€ ํ›จ์”ฌ ๋” ๋ฌด์„ญ์Šต๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ ์•ฑ์˜ ๋ชจ๋“  ํ™”๋ฉด์— ๋Œ€ํ•ด 5ํŽ˜์ด์ง€์˜ ๋ฌธ์„œ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋ฆด๋ฆฌ์Šค ์ดํ›„ ๋ช‡ ๋‹ฌ ์•ˆ์— ๋‚ด ์•ฑ์˜ ํŽ˜์ด์ง€๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€ ์ž‘์€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ฑ์ด ์„œ๋ฒ„๋ฅผ ๋„ˆ๋ฌด ๋งŽ์ด ํ˜ธ์ถœํ•ฉ๋‹ˆ๊นŒ? ์‰ฌ์šด ์ž‘์—… ๊ด€๋ จ ํ›…์œผ๋กœ ์ด๋™ํ•˜์—ฌ ๋ณ€๊ฒฝํ•˜๋ฉด ์ „์ฒด ์•ฑ์ด ํ•ด๋‹น ํ›…์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ „์ฒด ์•ฑ์ด ์ˆ˜์ •๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ข‹์€ ์ถ”์ƒํ™”๋ฅผ ๊ฐ€์ง„ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์•ฑ์—์„œ ๋น„์Šทํ•œ ๊ฒƒ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ๋‚ด๊ฐ€ ๋งํ•˜๋Š” ๊ฒƒ์€ ํ›„ํฌ๊ฐ€ ์ข‹์€ ์ถ”์ƒํ™”๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@gaearon ์ด ๋‚˜๋ณด๋‹ค ๋” ์ž˜

์œ„์˜ ์˜ˆ๋ฅผ ๋ณด๋ฉด ์œ„์˜ ์–ด๋–ค ๋ฐฉ๋ฒ•(์ƒํƒœ ์ €์žฅ ๋ฐ ํ›„ํฌ ์œ„์ ฏ)๋„ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•๋ณด๋‹ค ์„ฑ๋Šฅ์ด ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์š”์ ์€ ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์‚ฌ๋žŒ๋“ค์ด ์„ฑ๋Šฅ์ด ์ข‹์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋„๋ก ๊ถŒ์žฅํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ์—…๋ฐ์ดํŠธ(์˜ˆ: ์• ๋‹ˆ๋ฉ”์ด์…˜)๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ๊ฒฝ์šฐ StreamBuilder ์ฒ˜๋Ÿผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•˜๋Š” ํ•˜์œ„ ํŠธ๋ฆฌ๋งŒ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1 - HookWidget ๋ฐ StatefulWidget/StatelessWidget ๋ชจ๋‘์— ๋Œ€ํ•ด ์™„์ „ํžˆ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์ธ ์ƒˆ ์œ„์ ฏ ๋งŒ๋“ค๊ธฐ
2 - flutter_hooks ํŒจํ‚ค์ง€์—์„œ HookWidgetBuilder ์™€ ์œ ์‚ฌํ•œ ๊ฒƒ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ƒ์œ„ ๋ฐ ํ•˜์œ„ ์œ„์ ฏ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งค์šฐ ๋ฐ€์ ‘ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ  ์‚ฌํ•ญ: ์ด ์ฃผ์ œ์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ณ  ์ด ๋ฌธ์ œ์— ๋งŽ์€ ์—๋„ˆ์ง€๋ฅผ ์Ÿ์€ @Hixie ์™€ @rrousselGit ์—๊ฒŒ ์ •๋ง ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ด ํšŒ๋‹ด์˜ ๊ฒฐ๊ณผ๊ฐ€ ์ •๋ง ๊ธฐ๋Œ€๋ฉ๋‹ˆ๋‹ค.

@Hixie ์˜ ์‹œ์ž‘์ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฝค ๋ฉ‹์ง€๊ณ  ์šฐ์•„ํ•œ ์ƒ๊ฐ์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์•„์ง ๊ณต์œ ํ•  ์ค€๋น„๊ฐ€ ๋˜์ง€ ์•Š์•˜์ง€๋งŒ ๊ฝค ๊ดœ์ฐฎ์€ ์ฝ”๋“œ ์ƒ˜ํ”Œ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๊ณ , ๋„ˆ๋ฌด ์ด์งˆ์ ์œผ๋กœ ๋ณด์ด๋Š” ํ›„ํฌ๋ณด๋‹ค apple:apple ์„ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฌ์šธ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„œ๋ช…์ด ์žˆ๋Š” StatefulWidget์ด ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•ด ๋ณด์‹ญ์‹œ์˜ค.

class ExampleSimple extends StatefulWidget {
  final Duration duration1;
  final Duration duration2;
  final Duration duration3;

  const ExampleSimple({Key key, this.duration1, this.duration2, this.duration3}) : super(key: key);

  <strong i="9">@override</strong>
  _ExampleSimpleState createState() => _ExampleSimpleState();
}

๋ฐ”๋‹๋ผ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.

class _ExampleSimpleVanillaState extends State<ExampleSimpleVanilla> with SingleTickerProviderStateMixin {
  AnimationController _anim1;
  AnimationController _anim2;
  AnimationController _anim3;

  <strong i="13">@override</strong>
  void initState() {
    _anim1 = AnimationController(duration: widget.duration1, vsync: this);
    _anim1.forward();
    _anim2 = AnimationController(duration: widget.duration2, vsync: this);
    _anim2.forward();
    _anim3 = AnimationController(duration: widget.duration3, vsync: this);
    _anim3.forward();
    super.initState();
  }

  <strong i="14">@override</strong>
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(vertical: _anim2.value * 20, horizontal: _anim3.value * 30,),
      color: Colors.red.withOpacity(_anim1.value),
    );
  }

  <strong i="15">@override</strong>
  void didUpdateWidget(ExampleSimpleVanilla oldWidget) {
    if (oldWidget.duration1 != widget.duration1) {
      _anim1.duration = widget.duration1;
    }
    if (oldWidget.duration2 != widget.duration2) {
      _anim1.duration = widget.duration1;
    }
    if (oldWidget.duration3 != widget.duration3) {
      _anim1.duration = widget.duration1;
    }
    super.didUpdateWidget(oldWidget);
  }

  <strong i="16">@override</strong>
  void dispose() {
    _anim1.dispose();
    _anim2.dispose();
    _anim3.dispose();
    super.dispose();
  }
}

StatefulProperty๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฉ๋‹ˆ๋‹ค.

class _ExampleSimpleState extends State<ExampleSimple> with StatefulPropertyManager {
  StatefulAnimationProperty _anim1;
  StatefulAnimationProperty _anim2;
  StatefulAnimationProperty _anim3;

  <strong i="6">@override</strong>
  void initStatefulProperties({bool firstRun = false}) {
    _anim1 = initProperty(_anim1, StatefulAnimationProperty(duration: widget.duration1, playOnInit: true));
    _anim2 = initProperty(_anim2, StatefulAnimationProperty(duration: widget.duration2, playOnInit: true));
    _anim3 = initProperty(_anim3, StatefulAnimationProperty(duration: widget.duration3, playOnInit: true));
    super.initStatefulProperties(firstRun: firstRun);
  }

  <strong i="7">@override</strong>
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(vertical: _anim2.controller.value * 20, horizontal: _anim3.controller.value * 30,),
      color: Colors.red.withOpacity(_anim1.controller.value),
    );
  }
}

์ฐจ์ด์ ์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ์ฐธ๊ณ  ์‚ฌํ•ญ:

  1. ๋งจ ์œ„์—์„œ ํ•˜๋‚˜๋Š” 20์ค„, ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” 45๊ฐœ์ž…๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” 1315์ž์ด๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” 825์ž์ž…๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค์—์„œ๋Š” 3์ค„๊ณผ 200์ž๋งŒ ์ค‘์š”ํ•˜๋ฏ€๋กœ(๋นŒ๋“œ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ผ) ์ด๊ฒƒ์€ ์ด๋ฏธ ์‹ ํ˜ธ ์˜ ์—„์ฒญ๋‚œ ๊ฐœ์„ ์ž…๋‹ˆ๋‹ค.
  2. ๋ฐ”๋‹๋ผ ์˜ต์…˜์—๋Š” ๋ฒ„๊ทธ๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ ์ง€์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์žŠ๊ฑฐ๋‚˜ didChange ์ฒ˜๋ฆฌ๋ฅผ ์žŠ๊ฑฐ๋‚˜ didChange์—์„œ ์‹ค์ˆ˜๋ฅผ ํ•˜๋ฉด ์ฝ”๋“œ ๊ธฐ๋ฐ˜์— ๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ์œ ํ˜•์˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ƒํ™ฉ์ด ๋”์šฑ ์•…ํ™”๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ชจ๋“  ๋‹ค๋ฅธ ์œ ํ˜•์˜ ๊ฐ์ฒด๋ฅผ ๋ถ„ํ•ดํ•˜๋Š” ๋‹จ์ผ ํ•จ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๋Š” ์ด์™€ ๊ฐ™์ด ๋ฉ‹์ง€๊ณ  ์ˆœ์ฐจ์ ์œผ๋กœ ๋ช…๋ช…๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์ง€์ €๋ถ„ํ•ด์ง€๋ฉฐ ์‹ค์ˆ˜๋ฅผ ํ•˜๊ฑฐ๋‚˜ ํ•ญ๋ชฉ์„ ๋†“์น˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
  3. ๋ฐ”๋‹๋ผ ์˜ต์…˜์€ playOnInit์™€ ๊ฐ™์€ ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ด๋‚˜ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด ๋กœ์ง์„ ๋ณต์ œํ•˜๊ฑฐ๋‚˜ Animator๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๋งค์šฐ ๋‹จ์ผ ํด๋ž˜์Šค์—์„œ ์ผ๋ถ€ ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  4. ์—ฌ๊ธฐ์—์„œ SingleTickerProviderMixin์„ ์ดํ•ดํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ '๋งˆ๋ฒ•'์ด๊ณ  ๋ช‡ ๋‹ฌ ๋™์•ˆ Ticker๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ StatefulAnimationProperty์˜ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ๋ณผ ์ˆ˜ ์žˆ๊ณ  ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ปจํ…์ŠคํŠธ์—์„œ ์ง์ ‘ ํ‹ฐ์ปค ๊ณต๊ธ‰์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€์‹  StatefulPropertyManager๊ฐ€ ํ•˜๋Š” ์ผ์„ ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฒฐ์ •์ ์œผ๋กœ ์ด๊ฒƒ์€ ํ•œ ๋ฒˆ ๋ฐฐ์šฐ๊ณ  ๋ชจ๋“  ์œ ํ˜•์˜ ๊ฐ์ฒด์— ์ ์šฉ๋œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. SingleTickerProviderMixin์€ ์ฃผ๋กœ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ ์ปจํŠธ๋กค๋Ÿฌ ์‚ฌ์šฉ๊ณผ ๊ด€๋ จ์ด ์žˆ์œผ๋ฉฐ ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ์—๋Š” ์‚ฌ์šฉ์„ ๋” ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์ž์ฒด ๋ฏน์‹ฑ์ด ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ง€์ €๋ถ„ํ•ด์ง‘๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๋Š” ๋ณ„๊ฐœ์˜ "StatefulObjects"๋ฅผ ๊ฐ–๋Š” ๊ฒƒ(๋นŒ๋”๊ฐ€ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ!)์€ ํ›จ์”ฌ ๊นจ๋—ํ•˜๊ณ  ํ™•์žฅ์„ฑ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

StatefulAnimationProperty์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

class StatefulAnimationProperty extends BaseStatefulProperty<StatefulAnimationProperty> implements TickerProvider {
  final Duration duration;
  final TickerProvider vsync;
  final bool playOnInit;

  StatefulAnimationProperty({<strong i="7">@required</strong> this.duration, <strong i="8">@required</strong> this.vsync, this.playOnInit = false});

  AnimationController get controller => _controller;
  AnimationController _controller;

  Ticker _ticker;

  <strong i="9">@override</strong>
  Ticker createTicker(onTick) {
    _ticker ??= Ticker((elapsed)=>handleTick(elapsed, onTick));
    return _ticker;
  }

  handleTick(Duration elapsed, TickerCallback onTick) {
    managerWidget.buildWidget(); //TODO: This just calls setState() on the host widget. Is there some better way to do this?
    onTick(elapsed);
  }

  <strong i="10">@override</strong>
  void init(StatefulAnimationProperty old) {
    _controller = old?.controller ??
        AnimationController(
          duration: duration ?? Duration(seconds: 1),
          vsync: vsync ?? this,
        );
    if (playOnInit && old?.controller == null) {
      _controller.forward();
    }
    super.init(old);
  }

  <strong i="11">@override</strong>
  void update(StatefulAnimationProperty old) {
    if (duration != old.duration) {
      _controller.duration = duration;
    }
    if (vsync != old.vsync) {
      _controller.resync(vsync);
    }
    super.update(old);
  }

  <strong i="12">@override</strong>
  void dispose() {
    _controller?.dispose();
    _ticker?.dispose();
    super.dispose();
  }
}

๋งˆ์ง€๋ง‰์œผ๋กœ, ํ™•์žฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ€๋…์„ฑ์„ ๋”์šฑ ๋†’์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  void initStatefulProperties({bool firstRun = false}) {
    _anim1.init(duration: widget.duration1, playOnInit: true);
    _anim2.init(duration: widget.duration2, playOnInit: true);
    _anim3.init(duration: widget.duration3, playOnInit: true);
    super.initStatefulProperties(firstRun: firstRun);
  }

[ํŽธ์ง‘] ๋‚ด ๋ง์„ ํ•˜์ž๋ฉด ๋‚ด ๋ฐ”๋‹๋ผ ์˜ˆ์ œ์—๋Š” ๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. didUpdateWidget์˜ ๊ฐ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ์— ์˜ฌ๋ฐ”๋ฅธ ์ง€์† ์‹œ๊ฐ„์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์„ ์žŠ์—ˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ ๋ฆฌ๋ทฐ์—์„œ ์•„๋ฌด๋„ ๋ˆˆ์น˜์ฑ„์ง€ ๋ชปํ–ˆ๋‹ค๋ฉด ์•ผ์ƒ์—์„œ ๊ทธ ๋ฒ„๊ทธ๋ฅผ ์ฐพ๋Š” ๋ฐ ์–ผ๋งˆ๋‚˜ ๊ฑธ๋ ธ์„๊นŒ์š”? ์ฝ๋Š” ๋™์•ˆ ์•„๋ฌด๋„ ๊ทธ๊ฒƒ์„ ๋ฐœ๊ฒฌํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋Œ€๋กœ ๋‘๋Š” ๊ฒƒ์€ ํ˜„์‹ค ์„ธ๊ณ„์—์„œ ์ผ์–ด๋‚˜๋Š” ์ผ์— ๋Œ€ํ•œ ์™„๋ฒฝํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋นจ๊ฐ„์ƒ‰์œผ๋กœ ํ‘œ์‹œ๋œ ์ƒ์šฉ๊ตฌ์™€ ํ•จ๊ป˜ ์กฐ๊ฐ๋„์ž…๋‹ˆ๋‹ค.
image

์ด๊ฒƒ์€ ์ˆœ์ˆ˜ํ•œ ์ƒ์šฉ๊ตฌ๋ผ๋ฉด ๊ทธ๋ ‡๊ฒŒ ๋‚˜์˜์ง€ ์•Š์„ ๊ฒƒ์ด๊ณ  ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๊ทธ๊ฒƒ์ด ์—†์œผ๋ฉด ๋‹น์‹ ์—๊ฒŒ ์†Œ๋ฆฌ๋ฅผ ์งˆ๋ €์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ๋ชจ๋‘ ์„ ํƒ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค! ๊ทธ๋ฆฌ๊ณ  ์ƒ๋žตํ•˜๋ฉด ๋ฒ„๊ทธ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ๋งค์šฐ ๋‚˜์œ ์Šต๊ด€์ด๋ฉฐ DRY๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋นŒ๋”๊ฐ€ ๋“ค์–ด์˜ค๋Š” ๊ณณ์ด์ง€๋งŒ ๋‹จ์ˆœํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์—๋งŒ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์— ๋Œ€ํ•ด ๋งค์šฐ ํฅ๋ฏธ๋กญ๊ฒŒ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์€ 100๊ฐœ์˜ ๋ผ์ธ๊ณผ State์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ๋ฏน์Šค์ธ์ด ๊ธฐ์กด ํด๋ž˜์Šค๋ฅผ ์ค‘๋ณต๋˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด์ œ TickerProviderMixins๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. TweenAnimationBuilder๋Š” ์‹ค์ œ๋กœ ํ•˜์œ„ ์ปจํ…์ŠคํŠธ๋ฅผ _์›ํ•˜์ง€_ ์•Š๋Š” ํ•œ ๊ฑฐ์˜ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํฌ์ปค์Šค ์ปจํŠธ๋กค๋Ÿฌ ๋ฐ textInput ์ปจํŠธ๋กค๋Ÿฌ ๊ด€๋ฆฌ์™€ ๊ฐ™์€ ๊ธฐ์กด์˜ ๋งŽ์€ ๋ฌธ์ œ์ ์ด ์ƒ๋‹นํžˆ ์™„ํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Streams๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ›จ์”ฌ ๋” ๋งค๋ ฅ์ ์ด๊ณ  ๋œ ๋ณต์žกํ•ด์ง‘๋‹ˆ๋‹ค. ์ฝ”๋“œ ๊ธฐ๋ฐ˜ ์ „์ฒด์—์„œ Builders์˜ ์‚ฌ์šฉ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์ค„์–ด๋“ค์–ด ๋” ์‰ฝ๊ฒŒ grokable ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์ด์ „์— ๋‚˜์—ด๋œ FetchUser ์˜ˆ์ œ์™€ ๊ฐ™์ด ํ˜„์žฌ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋นŒ๋”๊ฐ€ ํ•„์š”ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ์ƒํƒœ ๊ฐœ์ฒด๋ฅผ _๋งค์šฐ_ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ Flutter ๊ฐœ๋ฐœ์ž ์„ค๋ฌธ์กฐ์‚ฌ์—์„œ ์ด๊ฒƒ์ด ๋งค์šฐ ํฅ๋ฏธ๋กœ์šด ์งˆ๋ฌธ์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ข‹์€ ์‹œ์ž‘์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฅธ ๋ถ€๋ถ„/์งˆ๋ฌธ์œผ๋กœ ๋‚˜๋ˆ„๊ณ  ์ด๊ฒƒ์ด Flutter ๊ฐœ๋ฐœ์ž๊ฐ€ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ์‹ค์ œ ๋ฌธ์ œ์ธ์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

๋ช…ํ™•ํ•ด์ง€๋ฉด ์ด ๋Œ€ํ™”๊ฐ€ ๋” ์œ ์ฐฝํ•˜๊ณ  ํ’๋ถ€ํ•ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐ ๋Œ“๊ธ€ ์•„๋ž˜์˜ ์ด๋ชจํ‹ฐ์ฝ˜ ๋ฐ˜์‘์€ ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ์ด๋ฅผ ๋ฌธ์ œ๋กœ ๋ณด๋Š”์ง€ ์—ฌ๋ถ€์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•œ ์•„์ด๋””์–ด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด 250๊ฐœ ์ด์ƒ์˜ ๊ธด ๋Œ“๊ธ€์„ ์ฝ์€ ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋งŽ์€ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

@esDotDev ๊ทธ๊ฒƒ์€ ๋‚ด๊ฐ€ ๊ฐ€์ง€๊ณ  ๋“ค์ง€๋งŒ ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๊ณ ๋ คํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ตฌํ˜„์—์„œ ๋ˆ„๋ฝ๋œ ํ•œ ๊ฐ€์ง€๋Š” ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” TickerMode(TickerProviderStateMixin์˜ ์š”์ ) ์ฒ˜๋ฆฌ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๊ณ ๊ตฐ๋ถ„ํˆฌํ•˜๋Š” ์ฃผ์š” ๋ฌธ์ œ๋Š” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ValueListenableBuilder๋Š” ์„ฑ๋Šฅ์„ ์ธก์ • ๊ฐ€๋Šฅํ•˜๊ฒŒ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž์‹ ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Property ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.

@Hixie
์ด์™€ ๊ฐ™์€ ์ ‘๊ทผ ๋ฐฉ์‹์˜ ํšจ์œจ์„ฑ ์†์‹ค์€ ๋ถˆ๊ฐ€ํ”ผํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ €๋Š” ์ฝ”๋“œ๋ฅผ ํ”„๋กœํŒŒ์ผ๋งํ•œ ํ›„ ์ตœ์ ํ™”ํ•˜๋ ค๋Š” Flutter์˜ ์‚ฌ๊ณ  ๋ฐฉ์‹์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค. Property ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋ช…ํ™•์„ฑ๊ณผ ๊ฐ„๊ฒฐํ•จ์˜ ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ํ”„๋กœํŒŒ์ผ๋งํ•˜๊ณ  ๋นŒ๋”๋กœ ๋ฆฌํŒฉํ„ฐ๋งํ•˜๊ฑฐ๋‚˜ ์œ„์ ฏ์˜ ์ผ๋ถ€๋ฅผ ์ž์ฒด ์œ„์ ฏ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ์˜ต์…˜์ด ํ•ญ์ƒ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์„œ๋Š” ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋ฐ˜์˜ํ•˜๊ณ  ์žฅ๋‹จ์ ์„ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๊ณ ๊ตฐ๋ถ„ํˆฌํ•˜๋Š” ์ฃผ์š” ๋ฌธ์ œ๋Š” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ValueListenableBuilder๋Š” ์„ฑ๋Šฅ์„ ์ธก์ • ๊ฐ€๋Šฅํ•˜๊ฒŒ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž์‹ ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Property ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.

ํ , ์†์„ฑ์˜ ์ „์ฒด ์š”์ ์€ ๋น„์‹œ๊ฐ์  ๊ฐœ์ฒด์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ญ”๊ฐ€๊ฐ€ ํŠธ๋ฆฌ์— ์ปจํ…์ŠคํŠธ ์Šฌ๋กฏ์„ ๊ฐ–๊ณ  ์‹ถ๋‹ค๋ฉด ๊ทธ ๊ฒƒ์€ ๋นŒ๋”์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค(์‚ฌ์‹ค ์ด๊ฒƒ๋“ค์ด ์ง€๊ธˆ ๋นŒ๋”์—ฌ์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์œ ์ผํ•œ ๊ฒƒ์ž…๋‹ˆ๊นŒ?)

๋”ฐ๋ผ์„œ ์ „์ฒด ๋ทฐ๋ฅผ ๋ฐ”์ธ๋”ฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ๋Œ€๋ถ€๋ถ„ ์‚ฌ์šฉํ•˜๋Š” StatefulValueListenableProperty๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํŠธ๋ฆฌ์˜ ์ผ๋ถ€ ํ•˜์œ„ ์„น์…˜์ด ๋‹ค์‹œ ์ž‘์„ฑ๋˜๊ธฐ๋ฅผ ์›ํ•˜๋Š” ๊ฒฝ์šฐ ValueListenableBuilder๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋˜ํ•œ ๋นŒ๋”๋ฅผ ๋ฆฌํ”„ ๋…ธ๋“œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์œ„์ ฏ ํŠธ๋ฆฌ ์ƒ๋‹จ์— 2 ๋˜๋Š” 3์„ ์ค‘์ฒฉํ•˜๋Š” ๊ฒƒ๋งŒํผ ๊ฐ€๋…์„ฑ์— ์ง€์žฅ์„ ์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ค‘์ฒฉ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

@TimWhiting Flutter์˜ ๋””์ž์ธ ์ฒ ํ•™์˜ ํฐ ๋ถ€๋ถ„์€ ์‚ฌ๋žŒ๋“ค์ด ์˜ฌ๋ฐ”๋ฅธ ์„ ํƒ์„ ํ•˜๋„๋ก ์•ˆ๋‚ดํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ๋” ๋‚˜์€ ์„ฑ๊ณผ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ๋ฉ€๋ฆฌ ๋– ๋‚˜์•ผ ํ•˜๋Š” ์Šคํƒ€์ผ์„ ๋”ฐ๋ฅด๋„๋ก ๋ถ€์ถ”๊ธฐ๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ์š”๊ตฌ ์‚ฌํ•ญ์„ ํ•œ ๋ฒˆ์— ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ํ™•์‹คํžˆ ์‹œ๋„ํ•ด ๋ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@Hixie
๊ฑด์ถ•์—…์ž์—๊ฒŒ ์ด์™€ ๊ฐ™์€ ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

class _ExampleSimpleState extends State<ExampleSimple> with StatefulPropertyManager {
  StatefulAnimationProperty _anim1;
  StatefulAnimationBuilderProperty _anim2;

  <strong i="7">@override</strong>
  void initStatefulProperties({bool firstRun = false}) {
    _anim1 = initProperty(_anim1, StatefulAnimationProperty(duration: widget.duration1, playOnInit: true));
    _anim2 = initProperty(_anim3, StatefulAnimationBuilderProperty(duration: widget.duration3, playOnInit: true));
    super.initStatefulProperties(firstRun: firstRun);
  }

  <strong i="8">@override</strong>
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red.withOpacity(_anim1.controller.value),
      child: _anim2(child: SomeChildWidget()),
    );
  }
}

์ž์„ธํžˆ ์•Œ๋ ค์ฃผ์‹ค ์ˆ˜ ์žˆ๋‚˜์š”? ์ œ์•ˆ์„ ์ดํ•ดํ–ˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Š” StatefulProperty๊ฐ€ ์‹œ๊ฐ์  ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ๋Š” ์†์„ฑ์— ๋Œ€ํ•œ ์„ ํƒ์  ๋นŒ๋“œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

return Column(
   children: [
      TopContent(),
      _valueProperty.build(SomeChildWidget()),
   ]
)

๊ฝค ๐Ÿ”ฅ ์ด๋ชจ,

์˜ˆ, ์ž‘๋™ํ•˜๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ๋นŒ๋”์˜ ๋‹ค๋ฅธ ์†์„ฑ์ด ์†์„ฑ์— ์˜ํ•ด ์„ค์ •๋œ๋‹ค๋Š” ์ ์„ ์ œ์™ธํ•˜๊ณ  ๋นŒ๋“œ ๋ฉ”์„œ๋“œ๋Š” ์ผ๋ฐ˜ ๋นŒ๋”์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ž์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
๋นŒ๋”์˜ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋นŒ๋“œ ๋ฉ”์†Œ๋“œ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋นŒ๋” ์ธ์ˆ˜๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๋ถ€์ ์œผ๋กœ ๋ฉ”์„œ๋“œ๋Š” ์ง€์ •๋œ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ผ๋ฐ˜ ๋นŒ๋”๋ฅผ ๋งŒ๋“ค๊ณ  ์ž์‹ ์ธ์ˆ˜๋ฅผ ์ผ๋ฐ˜ ๋นŒ๋”์— ์ „๋‹ฌํ•˜๊ณ  ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

Widget build(BuildContext context) {
  return ExpensiveParent(
    child: ValueListenableBuilder(
      valueListenable: foo,
      child: ExpensiveChild(),
      builder: (BuildContext context, value, Widget child) {
        return SomethingInTheMiddle(
          value: value,
          child: child,
        );
      }
    ),
  );
}

...๊ทธ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

@esDotDev ์†์„ฑ ์ž์ฒด๊ฐ€ ์‹œ์„ธ ๊ณต๊ธ‰์ž๊ฐ€ ๋˜๋Š” ๋‹น์‹ ์˜ ์•„์ด๋””์–ด๊ฐ€ ๋งˆ์Œ์—

์ด ํ›„ํฌ ์Šคํƒ€์ผ ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ์ธก๋ฉด ์ค‘ ํ•˜๋‚˜๋Š” ์ƒํƒœ ์ €์žฅ ๋…ผ๋ฆฌ๋ฅผ _์™„์ „ํžˆ_ ์บก์Šํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๊ฒฝ์šฐ AC์˜ ์ „์ฒด ๋ชฉ๋ก์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. AC ์ƒ์„ฑ
  2. ์‹œ์„ธ๋ฅผ ์ค˜
  3. ์œ„์ ฏ ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ
  4. ac ๋ฐ ์‹œ์„ธ์˜ ์ •๋ฆฌ ์ฒ˜๋ฆฌ
  5. ํ‹ฑ์— ๋ทฐ ๋‹ค์‹œ ์ž‘์„ฑ

ํ˜„์žฌ 1,3,4๋ฅผ ์ˆ˜๋™์œผ๋กœ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š”(๋˜๋Š” ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋Š”) ๊ฐœ๋ฐœ์ž์™€ 2์™€ โ€‹โ€‹5๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ˜ ๋งˆ๋ฒ•์˜ SingleTickerProviderMixin('์ด๊ฒƒ'์„ vsync๋กœ ์ „๋‹ฌํ•˜์—ฌ ๋ช‡ ๋‹ฌ ๋™์•ˆ ๋‚˜๋ฅผ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค! ). ๊ทธ๋ฆฌ๊ณ  SingleTickerProviderMixin ์ž์ฒด๋Š” ๋ถ„๋ช…ํžˆ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ˆ˜์ • ์‹œ๋„์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋ชจ๋“  ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ํด๋ž˜์Šค์— ๋Œ€ํ•ด TickerProvider๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ๋ช…ํ™•ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

Widget build(BuildContext context) {
  return ExpensiveParent(
    child: ValueListenableBuilder(
      valueListenable: foo,
      child: ExpensiveChild(),
      builder: (BuildContext context, value, Widget child) {
        return SomethingInTheMiddle(
          value: value,
          child: child,
        );
      }
    ),
  );
}

...๊ทธ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

class _ExampleSimpleState extends State<ExampleSimple> with StatefulPropertyManager {
  StatefulValueListenableBuilder _fooBuilder;

  <strong i="10">@override</strong>
  void initStatefulProperties({bool firstRun = false}) {
    _fooBuilder = initProperty(StatefulValueListenableProperty(valueListenable: widget.foo)); 
    super.initStatefulProperties(firstRun: firstRun);
  }

  <strong i="11">@override</strong>
  Widget build(BuildContext context) {
    return ExpensiveParent(
      child: SomethingInTheMiddle(
        _fooBuilder.value,
        _fooBuilder.builder(childBuilder: () => ExpensiveChild()),
      ),
    );
  }
}

@Hixie
์˜ˆ๋ฅผ ๋“ค์–ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ตœ์„ ์„ ๋‹คํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์ณค์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋นŒ๋”๊ฐ€ ์ž์‹์„ ์บ์‹œํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์–ธ์ œ ์‹ค์ œ๋กœ ์•„์ด๋ฅผ ์žฌ๊ฑดํ•ด์•ผ ํ•˜๋Š๋ƒ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ œ๊ธฐํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ์งˆ๋ฌธ์ด์—ˆ๋˜ ๊ฒƒ ๊ฐ™์€๋ฐ..

@Hixie ๋ณด์…จ๋‚˜์š” https://github.com/flutter/flutter/issues/51752#issuecomment -671104377
์ •๋ง ์ข‹์€ ์ ๋„ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์•„์š”.
์ €๋Š” ์˜ค๋Š˜ ValueListenableBuilder๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜์—ฌ ๋ฌด์–ธ๊ฐ€๋ฅผ ๊ตฌ์ถ•ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์ฝ๊ธฐ์— ์ข‹์ง€ ์•Š๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Hixie
์˜ˆ๋ฅผ ๋“ค์–ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ตœ์„ ์„ ๋‹คํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์ณค์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Property๊ฐ€ ์ •์˜๋œ ์ƒํƒœ์— ๋ฐ”์ธ๋”ฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ExpensiveParent๋Š” ํ•ญ์ƒ ์—ฌ๊ธฐ์—์„œ ๋‹ค์‹œ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ Builder ์˜ˆ์ œ์—์„œ์™€ ๊ฐ™์ด ์ž์‹์˜ ์บ์‹ฑ๋„ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋ถ€๋ชจ ์ƒํƒœ๊ฐ€ ๋นŒ๋“œ๋  ๋•Œ๋งŒ ์ž์‹์„ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์—์„œ๋Š” ์†์„ฑ์ด ์บ์‹œ๋ฅผ ๋ฌดํšจํ™”ํ•  ๋•Œ๋ฅผ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค(ํ•˜์ง€๋งŒ ์•„๋งˆ๋„ ์ด ํ•ด๊ฒฐ ๊ฐ€๋Šฅํ•œ๊ฐ€์š”?)

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ์ƒˆ๋กœ์šด ์ปจํ…์ŠคํŠธ๋ฅผ ๋„์ž…ํ•˜๋ ค๋Š” ๋นŒ๋”์—๊ฒŒ ์™„๋ฒฝํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. StatefulProperties(์ˆœ์ˆ˜ ์ƒํƒœ) ๋ฐ StatefulWidget(์ƒํƒœ ๋ฐ ๋ ˆ์ด์•„์›ƒ ํ˜ผํ•ฉ)์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ๋งค์šฐ ์šฐ์•„ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์˜๋„์ ์œผ๋กœ ํ•˜์œ„ ์ปจํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋งˆ๋‹ค ์ •์˜์— ๋”ฐ๋ผ ํŠธ๋ฆฌ ์•„๋ž˜์—์„œ ๋” ๋ฉ€๋ฆฌ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ ๋นŒ๋”์˜ ์ฃผ์š” ๋‹จ์  ์ค‘ ํ•˜๋‚˜(์ „์ฒด ํŠธ๋ฆฌ์— ๊ฐ•์ œ ์ค‘์ฒฉ)๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

@escamoteur (๊ทธ๋ฆฌ๊ณ  ๊ทธ ์˜๊ฒฌ์„ ์ž‘์„ฑํ•œ @sahandevs ) ์˜ˆ, ์ €๋Š” ๋” ์ผ์ฐ ๊ณต๋ถ€ํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด ์—†์• ๊ณ  ์‹ถ์–ดํ•˜๋Š” ๊ทธ๋Ÿฐ ๋…ผ๋ฆฌ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐ ํ™•์‹คํžˆ ๋„์›€์ด ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ๋…ผ๋ฆฌ(์˜ˆ: ์บ์‹ฑ๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ๊ฒƒ)๊ฐ€ ์•ฑ ์ƒํƒœ ๋น„์ฆˆ๋‹ˆ์Šค ๋…ผ๋ฆฌ์— ์žˆ๊ณ  ์œ„์ ฏ ๊ทผ์ฒ˜์—๋Š” ์—†์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•œ๋‹ค๋Š” ์ ์—์„œ ์˜ˆ์ œ ์ž์ฒด๊ฐ€ ์•ฝ๊ฐ„ ๋ชจํ˜ธํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํ•ซ ๋ฆฌ๋กœ๋“œ๋ฅผ ์ค‘๋‹จํ•˜์ง€ ์•Š๊ณ  ํ•ด๋‹น ์ฃผ์„์—์„œ ์ œ์•ˆ๋œ ๋Œ€๋กœ ๊ตฌ๋ฌธ์„ ๊ฐ„๋žตํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์„ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(์˜ˆ: ์‚ฌ์šฉ ์ค‘์ธ ํ›„ํฌ ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์‹œ ๋กœ๋“œ ๋™์•ˆ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ).

์ฆ‰, ์œ„์˜ @esDotDev ๋ฐ @TimWhiting ์ž‘์—…์ด ๋งค์šฐ ํฅ๋ฏธ๋กญ๊ณ  ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Hooks๋งŒํผ ์งง์ง€๋Š” ์•Š์ง€๋งŒ ๋” ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒƒ์„ ํฌ์žฅํ•˜๋Š” ๊ฒƒ์ด ์™„๋ฒฝํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ž˜ ์ž‘๋™ํ•œ๋‹ค๋ฉด Flutter Favorite๋„ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฑด๋ฌผ ์†์„ฑ๊ณผ ์„ฑ๋Šฅ ์˜ํ–ฅ์— ๋Œ€ํ•œ ๋ณต์žก์„ฑ๊ณผ ๋‹ค์–‘ํ•œ ์‚ฌ๋žŒ๋“ค์ด ๋‹ค์–‘ํ•œ ์Šคํƒ€์ผ์„ ์„ ํ˜ธํ•˜๋Š” ๋ฐฉ์‹์„ ๊ณ ๋ คํ•˜๋ฉด ๊ฐœ์„ ์ด ๊ทธ๋‹ค์ง€ ์ค‘์š”ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์ด ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ ๊ธฐ๋Šฅ์œผ๋กœ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋‹ค๋ฅธ ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ์ง€๋งŒ ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ์— ์—ฌ๋Ÿฌ ์Šคํƒ€์ผ์ด ์žˆ๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ƒˆ๋กœ์šด ๊ฐœ๋ฐœ์ž๋ฅผ ์˜ค๋„ํ•  ๋ฟ์ž…๋‹ˆ๋‹ค.

Flutter๋ฅผ ๋ฐฐ์šฐ๋Š” ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์€ ๋จผ์ € ์œ„์ ฏ์„ ์ดํ•ดํ•œ ๋‹ค์Œ ์ถ”์ƒ ๊ตฌ๋ฌธ์œผ๋กœ ๋ฐ”๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ ๋ณด๋‹ค๋Š” ์œ„์ ฏ์„ ์ถ”์ƒํ™”ํ•˜๋Š” ๋„๊ตฌ(Hook ๋˜๋Š” ๊ธฐํƒ€)๋ฅผ ๋ฐฐ์šฐ๋Š” ๊ฒƒ์ด๋ผ๋Š” ์ฃผ์žฅ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์‹œ์Šคํ…œ ์ž‘๋™ ๋ฐฉ์‹์˜ ํ•ต์‹ฌ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋†“์น˜๊ฒŒ ๋˜์–ด ์„ฑ๋Šฅ์ด ์ข‹์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ํ•ซ ๋ฆฌ๋กœ๋“œ๋ฅผ ์ค‘๋‹จํ•˜์ง€ ์•Š๊ณ  ํ•ด๋‹น ์ฃผ์„์—์„œ ์ œ์•ˆ๋œ ๋Œ€๋กœ ๊ตฌ๋ฌธ์„ ๊ฐ„๋žตํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์„ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(์˜ˆ: ์‚ฌ์šฉ ์ค‘์ธ ํ›„ํฌ ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์‹œ ๋กœ๋“œ ๋™์•ˆ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ).

ํ›„ํฌ๋Š” ๋ฌธ์ œ ์—†์ด ํ•ซ ๋ฆฌ๋กœ๋“œ์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
์ผ์น˜ํ•˜์ง€ ์•Š๋Š” runtimeType์ด ์žˆ๋Š” ์ฒซ ๋ฒˆ์งธ ํ›„ํฌ๋Š” ๋ชจ๋“  ํ›„์† ํ›„ํฌ๋ฅผ ํŒŒ๊ดดํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ถ”๊ฐ€, ์ œ๊ฑฐ ๋ฐ ์žฌ์ •๋ ฌ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ์กด์žฌํ•˜๋Š” ๋ถ€๋ถ„๋ณด๋‹ค ์™„์ „ํ•œ ์ถ”์ƒํ™”๊ฐ€ ๋ฐ”๋žŒ์งํ•˜๋‹ค๋Š” ์ฃผ์žฅ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์†์„ฑ์˜ ์ปจํ…์ŠคํŠธ์—์„œ Animator๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์™„์ „ํžˆ ๋ฌด์‹œํ•˜๊ฑฐ๋‚˜ ๋›ฐ์–ด๋“ค๋ฉด ๋ฉ๋‹ˆ๋‹ค.

AnimatorController๊ฐ€ StatefulWidget์˜ ์ปจํ…์ŠคํŠธ์—์„œ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์„ ์ดํ•ดํ•˜๋ ค๋ฉด ๊ธฐ๋ณธ ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ๋ฅผ ์ดํ•ดํ•ด์•ผ ํ•˜์ง€๋งŒ ๊ธฐ๋ณธ ํ‹ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์–ด๋–ค ์˜๋ฏธ์—์„œ ๋‘ ์„ธ๊ณ„ ๋ชจ๋‘์—์„œ ์ตœ์•…์ž…๋‹ˆ๋‹ค. '๊ทธ๋ƒฅ ์ž‘๋™'ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋งˆ๋ฒ•์€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์ง€๋งŒ ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋ฅผ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ๋งŒ๋“ค๊ณ  ์ผ๋ถ€ mixin(๊ทธ ์ž์ฒด๊ฐ€ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ๊ฐœ๋…์ž„)๊ณผ ๋งˆ๋ฒ•์˜ vsync ์†์„ฑ์„ ๋งน๋ชฉ์ ์œผ๋กœ ์‹ ๋ขฐํ•˜๋„๋ก ํ•˜๊ธฐ์—๋Š” ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ ๊ธฐ๋ฐ˜์˜ ๋‹ค๋ฅธ ์˜ˆ์ œ๋Š” ์ž˜ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ StatefulWidget์— ๋Œ€ํ•ด ์ผ๋ถ€ ๋„์šฐ๋ฏธ ๋ฏน์Šค์ธ์ด ์ œ๊ณต๋˜์—ˆ์ง€๋งŒ ํ•ญ์ƒ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ๋‹ค๋ฅธ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์ด ์žˆ๋Š” ๋ชจ๋“  ์ƒํ™ฉ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ๋ถ€ํŠธ์ŠคํŠธ๋ž˜ํ•‘(์ง€๋ฃจํ•œ ๋ถ€๋ถ„)์„ ๋ฐฐ์šฐ๊ณ  Mixin(ํฅ๋ฏธ๋กœ์šด/๋ณต์žกํ•œ ๋ถ€๋ถ„)์„ ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์œ„์˜ @esDotDev ๋ฐ @TimWhiting ์ž‘์—…์ด ๋งค์šฐ ํฅ๋ฏธ๋กญ๊ณ  ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Hooks๋งŒํผ ์งง์ง€๋Š” ์•Š์ง€๋งŒ ๋” ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ๋” ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์กฐ๊ฑด๋ถ€๋กœ ๋˜๋Š” ์ˆ˜๋ช… ์ฃผ๊ธฐ ์™ธ๋ถ€์—์„œ ์†์„ฑ์„ ์ƒ์„ฑ/์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚˜์œ ์ƒํƒœ๊ฐ€ ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์†์„ฑ์„ ์กฐ๊ฑด๋ถ€๋กœ ํ˜ธ์ถœํ•˜๋ฉด ์กฐ๊ฑด์ด false์ธ ๊ฒฝ์šฐ ์†์„ฑ์ด ์‚ญ์ œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“  ์†์„ฑ์€ ๋ชจ๋“  ์žฌ๊ตฌ์ถ•์—์„œ ์—ฌ์ „ํžˆ ์žฌํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ NNBD ์ดํ›„ ๋ชจ๋“  ๊ณณ์—์„œ ! ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ ์ „์— ์‚ฌ์šฉ์ž๊ฐ€ ์†์„ฑ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋“ฑ ์—ฌ๋Ÿฌ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋ˆ„๊ตฐ๊ฐ€ didUpdateWidget ๋‚ด๋ถ€์˜ ์†์„ฑ์„ ์ฝ๋Š”๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

  • initProperties ๊ฐ€ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ „์— ์‹คํ–‰๋˜์—ˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋นŒ๋“œ๋‹น ์†์„ฑ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  • didUpdateWidget ํ›„์— initProperties ๊ฐ€ ์‹คํ–‰๋˜์—ˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋Ÿฐ ๋‹ค์Œ didUpdateWidget ๋‚ด๋ถ€์˜ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด ์˜ค๋ž˜๋œ ์ƒํƒœ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ, ์šฐ๋ฆฌ๋Š” ๋ชจ๋“  ํ›„ํฌ ๋ฌธ์ œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ:

  • ์šฐ๋ฆฌ๋Š” `StatelessWidget.xml' ๋‚ด์—์„œ ์†์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ StreamBuilder/ValueListenableBuilder/...์˜ ๊ฐ€๋…์„ฑ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ฃผ์š” ๊ด€์‹ฌ์‚ฌ์˜€์Šต๋‹ˆ๋‹ค.
  • ์ˆ˜๋งŽ์€ ์—ฃ์ง€ ์ผ€์ด์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค
  • ์‚ฌ์šฉ์ž ์ •์˜ ์†์„ฑ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค(์—ฌ๋Ÿฌ ์†์„ฑ์„ ํ•จ์ˆ˜๋กœ ์ถ”์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค)
  • ์žฌ๊ตฌ์„ฑ์„ ์ตœ์ ํ™”ํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ, ์ฃผ์–ด์ง„ ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ํ–‰๋™์ด ๋‹ค๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

class Example extends StatelessWidget {
  <strong i="29">@override</strong>
  Widget build(context) {
    final value1 = keyword TweenAnimationBuilder(tween: Tween(begin: 0, end: 1));
    final value2 = keyword TweenAnimationBuilder(tween: Tween(begin: 0, end: 1));
    final value3 = keyword TweenAnimationBuilder(tween: Tween(begin: 0, end: 1));

    return Container(
     margin: EdgeInsets.symmetric(vertical: value2 * 20, horizontal: value3 * 30),
     color: Colors.red.withOpacity(value1),
      child: _anim2(child: SomeChildWidget()),
    );
  }
}

๊ทธ๋Ÿฌ๋‚˜ ์ด ๊ตฌ๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ›จ์”ฌ ๋” ๋งŽ์€ ๊ฒƒ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์กฐ๊ธฐ ๋ฐ˜ํ™˜:

class Example extends StatelessWidget {
  <strong i="34">@override</strong>
  Widget build(context) {
    final value1 = keyword TweenAnimationBuilder(tween: Tween(begin: 0, end: 1));

    if (condition) {
      return Container();
    }

    final value2 = keyword TweenAnimationBuilder(tween: Tween(begin: 0, end: 1));

    ...
  }
}

ํ๊ธฐ ๊ฒƒ์ด๋‹ค value2 ๊ฒฝ์šฐ condition ๊ฑฐ์ง“์œผ๋กœ ์ „ํ™˜

๋นŒ๋” ๋ฒˆ๋“ค์„ ํ•จ์ˆ˜๋กœ ์ถ”์ถœ:

Widget build(context) {
  final foo = keyword FooBuilder();
  final bar = keyword BarBuilder();

  return Text('$foo $bar');
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Builder<String> LabelBuilder() builder* {
  final foo = keyword FooBuilder();
  final bar = keyword BarBuilder();

  return '$foo $bar';
}

Widget build(context) {
  final label = keyword LabelBuilder();

  return Text(label);
}

์žฌ๊ตฌ์ถ• ์ตœ์ ํ™”

child ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์—ฌ์ „ํžˆ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Widget build(context) {
  final value = keyword StreamBuilder();

  return Builder(
    builder: (context, child) {
      final value2 = keyword TweenAnimationBuilder();
      final value = keyword ValueListenableBuilder();

      return Whatever(child: child);
    },
    child: ExpensiveChild()
  );
}

์–ธ์–ด์˜ ์ผ๋ถ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ๋ฌธ ์„คํƒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  return Scaffold(
    body: {
      final value = keyword TweenAnimationBuilder();
      final value2 = keyword ValueListenableBuilder();

      return Text();
    },
  );
}

๋ณด๋„ˆ์Šค: ์–ธ์–ด ๊ธฐ๋Šฅ์œผ๋กœ ์กฐ๊ฑด๋ถ€ ํ˜ธ์ถœ์ด ์ง€์›๋ฉ๋‹ˆ๋‹ค.

์–ธ์–ด์˜ ์ผ๋ถ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ง€์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Widget build(context) {
  String label;

  if (condition) {
    label = keyword LabelBuilder();
  } else {
    label = keyword AnotherBuilder();
  }

  final value2 = keyword WhateverBuilder();

  return ...
}

๊ทธ๋‹ค์ง€ ์œ ์šฉํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์ง€์›๋ฉ๋‹ˆ๋‹ค. ๊ตฌ๋ฌธ์ด ์ปดํŒŒ์ผ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ฌ๋ฆฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์— ์˜์กดํ•˜์—ฌ keyword ์˜ ๊ฐ ์‚ฌ์šฉ๋ฒ•์„ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋นŒ๋”์˜ ๊ฐ€๋…์„ฑ๊ณผ ๊ด€๋ จํ•˜์—ฌ ๋‹ค์Œ์€ ์ด์ „ ์˜ˆ์ œ์ด์ง€๋งŒ ๋นŒ๋”๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋ชจ๋“  ์•ˆ์ •์„ฑ๊ณผ ์ฝ”๋“œ ์‚ฌ์šฉ ์š”๊ตฌ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€๋งŒ, ๋‚ด ํ˜•ํŽธ์—†๋Š” ์œ„์ ฏ ํŠธ๋ฆฌ์— ์–ด๋–ค ์˜ํ–ฅ์„ ๋ฏธ์ณค๋Š”์ง€ ์‚ดํŽด๋ณด์„ธ์š”.'(

class _ExampleSimpleBuilderState extends State<ExampleSimpleBuilder> {
  <strong i="6">@override</strong>
  Widget build(BuildContext context) {
    return TweenAnimationBuilder<double>(
        tween: Tween(begin: 0, end: 1),
        duration: widget.duration1,
        builder: (_, value1, __) {
          return TweenAnimationBuilder<double>(
              tween: Tween(begin: 0, end: 1),
              duration: widget.duration2,
              builder: (_, value2, __) {
                return TweenAnimationBuilder<double>(
                    tween: Tween(begin: 0, end: 1),
                    duration: widget.duration3,
                    builder: (_, value3, __) {
                      return Container(
                        margin: EdgeInsets.symmetric(vertical: value2 * 20, horizontal: value3 * 30),
                        color: Colors.red.withOpacity(value1),
                      );
                    });
              });
        });
  }
}

์ค‘์š”ํ•œ ์ฝ”๋“œ๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค(์ ์–ด๋„ ๋‚ด ๋ˆˆ์—๋Š”). ๋˜ํ•œ, fwiw, ๋‚˜๋Š” ์ด๊ฒƒ์„ ์ž‘์„ฑํ•  ๋•Œ 3๋ฒˆ ์ •๋„ ๋‹ค์‹œ ์‹œ์ž‘ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๋ธŒ๋ž˜ํ‚ท์ด ์–ด๋””์— ์†ํ•˜๋Š”์ง€, ๋‚ด ์„ธ๋ฏธ ์ฝœ๋ก ์ด ์–ด๋””๋กœ ๊ฐ€์•ผ ํ•˜๋Š”์ง€ ๋“ฑ์„ ๊ณ„์†ํ•ด์„œ ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ค‘์ฒฉ ๋นŒ๋”๋Š” ๋‚ด๋ถ€์—์„œ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ์ด ์žฌ๋ฏธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์ž˜๋ชป๋œ ์„ธ๋ฏธ์ฝœ๋ก ๊ณผ dartfmt๋Š” ์ „์ฒด๋ฅผ ์™„์ „ํžˆ ๋ถ€์ˆด๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ๋” ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด๊ฒƒ์ด ์™œ ์ด๊ฒƒ์ด ํ•ต์‹ฌ ํ”Œ๋Ÿฌ๊ทธ์ธ imo๊ฐ€ _ํ•ด์•ผ_ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์™„๋ฒฝํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ํ•„์š”ํ•œ ๋„๋ฉ”์ธ ์ง€์‹์€ _deep_์ž…๋‹ˆ๋‹ค. ์ €๋Š” ์ด์™€ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ์บ์‹ฑ ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ์Šคํฌ๋ฆฝํŒ… ์ง€์‹์ด ์žˆ์ง€๋งŒ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์—ฃ์ง€ ์ผ€์ด์Šค ๋˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๋‚˜์œ ์ƒํƒœ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋„๋ฉ”์ธ ์ง€์‹์ด ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. Remi ๋ง๊ณ ๋„ Flutter ํŒ€ ๋ง๊ณ ๋„ ์ด๋Ÿฐ ๊ฑธ ์•„๋Š” ๊ฐœ๋ฐœ์ž๋Š” ์ „ ์„ธ๊ณ„์— 4๋ช… ์ •๋„ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์•„์š”! (๋ถ„๋ช…ํžˆ ๊ณผ์žฅ).

Stateless ์œ„์ ฏ์„ ์ง€์›ํ•˜๋Š” ๋ฌธ์ œ๋Š” ์ข‹์€ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ํ•œํŽธ์œผ๋กœ๋Š” StatefulWidgets๊ฐ€ ์ด์ƒํ•˜๊ฒŒ ์žฅํ™ฉํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ•œํŽธ, ์—ฌ๊ธฐ์—์„œ ์šฐ๋ฆฌ๋Š” ์ง„์ •์œผ๋กœ ์ˆœ์ˆ˜ํ•œ ์žฅํ™ฉํ•จ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. 2๊ฐœ์˜ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ„๊ทธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์—‰๋ง์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์œผ๋ฉฐ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. StatelessWidget์—์„œ ํ•˜๊ณ  ์‹ถ์€ ํฅ๋ฏธ๋กœ์šด ์ž‘์—…์ด ์ „ํ˜€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚˜๋Š” ์ด๊ฒƒ์ด ์ค‘์š”ํ•œ ๋ฌธ์ œ๋ผ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋งค๋„๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค... ํ™•์‹คํžˆ ์žˆ์œผ๋ฉด ์ข‹๊ฒ ์ง€๋งŒ, ์ด๊ฒƒ์€ ๋งˆ์ง€๋ง‰ 5% imo์ด๋ฉฐ, ๊ผผ์งํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด์— ... ํ‚ค์›Œ๋“œ ์ง€์›์ด ์žˆ๋Š” remi์˜ ๊ตฌ๋ฌธ์€ ์ ˆ๋Œ€์ ์œผ๋กœ ์•„๋ฆ„๋‹ต๊ณ  ์œ ์—ฐํ•˜๊ณ  ๊ฐ•๋ ฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  StatelessWidget ์ง€์›์„ ๋ฌด๋ฃŒ๋กœ ์ œ๊ณตํ•œ๋‹ค๋ฉด ๊ทธ๊ฑด ์ถ”๊ฐ€ ์‚ฌํ•ญ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค ๐Ÿ”ฅ

StatelessWidget์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•œ IMO์ž…๋‹ˆ๋‹ค. ์„ ํƒ ์‚ฌํ•ญ์ด์ง€๋งŒ ์—ฌ์ „ํžˆ ๋งค์šฐ ์ข‹์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์ด ์ค‘์š”ํ•˜์ง€ ์•Š๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์€ ์ด๋ฏธ StatelessWidget ๋Œ€์‹  ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์‹ธ์šฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์‚ฌ๋žŒ๋“ค์ด ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด StatefulWidget์„ ์‚ฌ์šฉํ•˜๋„๋ก ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์€(๋Œ€๋ถ€๋ถ„์˜ ๋นŒ๋”๊ฐ€ ๋™์ผํ•œ ์†์„ฑ์„ ๊ฐ€์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๊ธฐ ๋•Œ๋ฌธ์—) ๊ฐˆ๋“ฑ์„ ์‹ฌํ™”์‹œํ‚ฌ ๋ฟ์ž…๋‹ˆ๋‹ค.

๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹คํŠธ์—์„œ ๊ณ ์ฐจ ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ์„ธ์ƒ(https://github.com/dart-lang/language/issues/418)์—์„œ๋Š” ํด๋ž˜์Šค๋ฅผ ์™„์ „ํžˆ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<strong i="9">@StatelessWidget</strong>
Widget Example(BuildContext context, {Key key, String param}) {
  final value = keyword StreamBuilder();

  return Text('$value');
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Widget build(context) {
  // BuildContext and Key are automatically injected
  return Example(param: 'hello');
}

์ด๊ฒƒ์€ ํ•จ์ˆ˜ ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ ์ƒ์„ฑ๊ธฐ์ธ function_widget์—์„œ ์ง€์›ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. HookWidget ๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์ฐจ์ด์ ์€ Dart์—์„œ ๊ณ ์ฐจ ํ•จ์ˆ˜๋ฅผ ์ง€์›ํ•˜๋ฉด ์ด๋Ÿฌํ•œ ๊ตฌ๋ฌธ์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@Hixie ๊ฐ€ ๋” ์•ˆ์ •์ ์ด๋ผ๋Š” ์˜๋ฏธ๊ฐ€ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ์ถ”์ธกํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๊ฐ€ ๊ฐ–๋Š” ์ž‘์—… ์ˆœ์„œ/์กฐ๊ฑด๋ถ€ ๋ฌธ์ œ๋กœ ๊ณ ํ†ต๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์•„ํ‚คํ…์ฒ˜ POV์—์„œ ๋งค์šฐ '์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š”' ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ฐฐ์šฐ๊ณ  ํ•œ ๋ฒˆ ํ•™์Šตํ•˜๋ฉด ์œ„๋ฐ˜ํ•˜์ง€ ์•Š์Œ).

๊ทธ๋Ÿฌ๋‚˜ ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ์ œ์•ˆ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” new ํ‚ค์›Œ๋“œ์˜ ๊ฒฝ์šฐ๊ฐ€ ๋งค์šฐ ๊ฐ•๋ ฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

  • State์— ์ ‘๋ชฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ์œ ์—ฐํ•˜๊ณ  ๊ตฌ์„ฑ ๊ฐ€๋Šฅ
  • ๋”์šฑ ๊ฐ„๊ฒฐํ•ด์ง„ ๊ตฌ๋ฌธ
  • Stateless์—์„œ ์ž‘๋™ํ•˜๋Š” ๋งค์šฐ ์ข‹์€ ์˜ต์…˜์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งˆ์Œ์— ๋“ค์ง€ ์•Š๋Š” ์ ์€ ์šฐ๋ฆฌ๊ฐ€ ๋ช‡ ๊ฐ€์ง€ ๊ฐ„๋‹จํ•œ ๊ฐœ์ฒด์˜ ์†์„ฑ์„ ์—ฌ๋Ÿฌ ๋ฒˆ/๋นŒ๋“œ๋กœ ์„ค์ •ํ•˜๋Š” ๋น„์šฉ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•˜๊ณ  ์žˆ์ง€๋งŒ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐฑ๋งŒ ์ˆ˜์ค€์˜ ์ปจํ…์ŠคํŠธ์™€ ๋งŽ์€ ๋ ˆ์ด์•„์›ƒ ๋น„์šฉ์„ ์ƒ์„ฑํ•˜๋Š” ์†”๋ฃจ์…˜์„ ์˜นํ˜ธํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์˜คํ•ดํ•˜๊ณ  ์žˆ๋Š” ๊ฑธ๊นŒ?

๋‹ค๋ฅธ ๋‹จ์ ์€ ์ด๋Ÿฌํ•œ ๋งˆ๋ฒ•์˜ ์•„์ด๋””์–ด์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋งˆ๋ฒ• ๊ฐ™์€ ์ผ์„ ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์ƒˆ ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์‰ฝ๊ฒŒ ๊ฐ•์กฐ ํ‘œ์‹œํ•˜๊ณ  ์š”์ฒญํ•˜๊ณ  ๊ทธ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€, ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒˆ๋กœ์šด ํ‚ค์›Œ๋“œ๊ฐ€ ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๊ฒƒ์€ Flutter์—์„œ ๋‚ด๋…„์— ๋Œ€ํ•ด ๋ˆ„๊ตฌ๋‚˜ ์ด์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์ด ๋  ๊ฒƒ์ด๋ฉฐ, ๊ฑฐ๊ธฐ์„œ ์ƒ์„ฑ๋˜๋Š” ๋ฉ‹์ง„ ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ํญ๋ฐœ์„ ๋ณด๊ฒŒ ๋  ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค.

@Hixie ๊ฐ€ ๋” ์•ˆ์ •์ ์ด๋ผ๋Š” ์˜๋ฏธ๊ฐ€ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ์ถ”์ธกํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๊ฐ€ ๊ฐ–๋Š” ์ž‘์—… ์ˆœ์„œ/์กฐ๊ฑด๋ถ€ ๋ฌธ์ œ๋กœ ๊ณ ํ†ต๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์•„ํ‚คํ…์ฒ˜ POV์—์„œ ๋งค์šฐ '์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š”' ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ฐฐ์šฐ๊ณ  ํ•œ ๋ฒˆ ํ•™์Šตํ•˜๋ฉด ์œ„๋ฐ˜ํ•˜์ง€ ์•Š์Œ).

๊ทธ๋Ÿฌ๋‚˜ ํ›„ํฌ๋Š” ์ •์ ์œผ๋กœ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์˜ค์šฉ๋  ๋•Œ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์ด์ „์— ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด Property๋Š” ๋˜‘๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๊ฒช์Šต๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๋Š” ํ•ฉ๋ฆฌ์ ์œผ๋กœ ์“ธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค:

Property property;

<strong i="12">@override</strong>
void initProperties() {
  if (condition) {
    property = init(property, MyProperty());
  }
}

condition ๋ฅผ true์—์„œ false๋กœ ์ „ํ™˜ํ•˜๋ฉด ์†์„ฑ์ด ์‚ญ์ œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฃจํ”„์—์„œ ์‹ค์ œ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค. ์ผํšŒ์„ฑ ๊ณผ์ œ์ด๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ์˜๋ฏธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฃจํ”„์—์„œ ์†์„ฑ์„ ์‹คํ–‰ํ•˜๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๊ทธ๋ฆฌ๊ณ  ์†์„ฑ์„ ์–ด๋–ค ์ˆœ์„œ๋กœ๋“  ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์€ ์œ„ํ—˜ํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Property first;
Property second;

<strong i="20">@override</strong>
void initProperties() {
  // The state of first depends on second, but second is updated after first
  // So we could end up in a bad state, similar to how the build method of a Widget should depend
  // on the context.size
  first = init(property, MyProperty(second?.value));

  second = init(property, Whatever());
}
> class _ExampleSimpleBuilderState extends State<ExampleSimpleBuilder> {
>   <strong i="5">@override</strong>
>   Widget build(BuildContext context) {
>     return TweenAnimationBuilder<double>(
>         tween: Tween(begin: 0, end: 1),
>         duration: widget.duration1,
>         builder: (_, value1, __) {
>           return TweenAnimationBuilder<double>(
>               tween: Tween(begin: 0, end: 1),
>               duration: widget.duration2,
>               builder: (_, value2, __) {
>                 return TweenAnimationBuilder<double>(
>                     tween: Tween(begin: 0, end: 1),
>                     duration: widget.duration3,
>                     builder: (_, value3, __) {
>                       return Container(
>                         margin: EdgeInsets.symmetric(vertical: value2 * 20, horizontal: value3 * 30),
>                         color: Colors.red.withOpacity(value1),
>                       );
>                     });
>               });
>         });
>   }
> }

๋„ˆ๋ฌด ์ด์ƒํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค. AnimatedContainer๊ฐ€ ์ด๋ฏธ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๊นŒ?

๋‹น์—ฐํ•˜์ง€. ์—ฌ๊ธฐ์˜ ์˜ˆ๋Š” "X"๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์ผ๋ถ€ ์œ„์ ฏ์—์„œ 3๊ฐœ์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. X๋Š” ์ƒ์šฉ๊ตฌ์˜ ์–‘์„ ๊ฐ•์กฐํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์ œ์—์„œ ์˜๋„์ ์œผ๋กœ ๋‹จ์ˆœํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€์— ์ง‘์ค‘ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์‹ค์ œ ์˜ˆ์—์„œ ์œ„์ ฏ "์ฝ”์–ด"๋Š” 100์ค„ ์ •๋„์ด๊ณ  ์• ๋‹ˆ๋ฉ”์ด์…˜ ์†์„ฑ์€ ๊ทธ๋ ‡๊ฒŒ ๋‹จ์ˆœํ•˜์ง€ ์•Š์œผ๋ฉฐ ์—ฌ๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ ๋ฐ ๊ธฐํƒ€ ๊ธฐ๋Šฅ์ด ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์•”์‹œ์  ์œ„์ ฏ ์ค‘ ํ•˜๋‚˜์—์„œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค(AnimatedContainer ์ด์™ธ์˜ ๋‹ค๋ฅธ ๋ชฉ์ ์€ ๋งค์šฐ ๋‹จ์ผ ๋ชฉ์ ์ด๋ฏ€๋กœ ์–ด๋ ต์ง€ ์•Š์Œ).

์š”์ ์€ ์ด์™€ ๊ฐ™์€ ๊ฒƒ์„ ๊ตฌ์ถ•ํ•  ๋•Œ ๋นŒ๋”๊ฐ€ ์ž˜ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ฐ€๋…์„ฑ(๋ฐ ์“ฐ๊ธฐ ๊ฐ€๋Šฅ์„ฑ) ๊ตฌ๋ฉ์— ์ง‘์–ด๋„ฃ๊ณ  ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ ํ•ฉํ•˜๋ฏ€๋กœ "์ž‘์„ฑ"ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ž˜. Compose๋Š” 2๊ฐœ ์ด์ƒ์˜ ํ•ญ๋ชฉ์œผ๋กœ ๊ตฌ์„ฑ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€์— ์ง‘์ค‘ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์‹ค์ œ ์˜ˆ์—์„œ ...

...๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ ์›์ ์œผ๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค. ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๊นŒ?

๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ์‹ค์ œ ์˜ˆ๊ฐ€ ํ•„์š”ํ•˜์‹ญ๋‹ˆ๊นŒ?
https://github.com/gskinnerTeam/flutter_vignettes

์ž„์˜์˜ ๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์€ ์˜ˆ์ œ๋ฅผ ๋‚œ๋…ํ™”ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ์œ„์ ฏ ๋‚ด์—์„œ ์—ฌ๋Ÿฌ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ(๋˜๋Š” ์ƒ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค๋ฅธ ์ƒํƒœ ์ €์žฅ ๊ฐ์ฒด)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋งŽ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹น์—ฐํ•˜์ง€. ์—ฌ๊ธฐ์˜ ์˜ˆ๋Š” "X"๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์ผ๋ถ€ ์œ„์ ฏ์—์„œ 3๊ฐœ์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. X๋Š” ์ƒ์šฉ๊ตฌ์˜ ์–‘์„ ๊ฐ•์กฐํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์ œ์—์„œ ์˜๋„์ ์œผ๋กœ ๋‹จ์ˆœํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์œ„์ ฏ "์ฝ”์–ด"๋Š” 100์ค„ ๋˜๋Š” ๊ทธ ์ด์ƒ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๊ฒŒ์‹œ๋ฌผ์—์„œ "ํ•ต์‹ฌ"์„ ๊ฐ€๋ฆฌ๋Š” ์ƒ์šฉ๊ตฌ ์˜ˆ์ œ๋ฅผ โ€‹โ€‹๊ฒŒ์‹œํ–ˆ์ง€๋งŒ ์ด์ œ ํ•ต์‹ฌ์ด ์ˆ˜๋ฐฑ ์ค„์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ๋งํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋ž˜์„œ ์‹ค์ œ๋กœ, ์ƒ์šฉ๊ตฌ๋Š” ์ฝ”์–ด์— ๋น„ํ•ด ๋ฏธ๋ฏธํ• ๊นŒ์š”? ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
๋‹น์‹ ์€ ๋Š์ž„์—†์ด ๋‹น์‹ ์˜ ์ฃผ์žฅ์„ ๋ฐ”๊พธ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€์— ์ง‘์ค‘ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์‹ค์ œ ์˜ˆ์—์„œ ...

...๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ ์›์ ์œผ๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค. ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๊นŒ?

๋‹ค์–‘ํ•œ ์•„์ด๋””์–ด๋ฅผ ๊ฐ€์ง€๊ณ  ๋…ธ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๋งŽ์ด ๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜๋„๋Š” ๋…์ž๊ฐ€ ์‹ค์ œ ์ƒํ™ฉ์—์„œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š”์ง€ ์ƒ์ƒํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด์ง€ ์ฃผ๋ณ€์— ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํ…Œ์ด๋„ˆ๋งŒ์œผ๋กœ ๋งŒ๋“ค๊ธฐ์—๋Š” ๋„ˆ๋ฌด ๋ณต์žกํ•˜๋‹ค๋ฉด ์–ด๋–จ๊นŒ์š”?

์ด์ œ ์ž‘๊ฐ€๋“ค์€ ์ข‹์€ ์˜ˆ๋‚˜ ๋‚˜์œ ๊ฒƒ์œผ๋กœ ๋ณด์—ฌ์งˆ ์ˆ˜ ์žˆ๋Š” ์ง„์ •ํ•œ ์‹ค์ œ ์˜ˆ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๊ฒƒ์— ๋Œ€ํ•œ ์˜๊ฒฌ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹น๋ฉดํ•œ ๋ฌธ์ œ๋ฅผ ์™„์ „ํžˆ ํ•ด๊ฒฐํ•˜์‹ญ์‹œ์˜ค. ์ด๊ฒƒ์€ ํ›„ํฌ ์ง€์ง€์ž์™€ ๋ฐ˜๋Œ€์ž ์‚ฌ์ด์— ํ˜ผ๋ˆ์˜ ์ฃผ์š” ์›์ธ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ฐ๊ฐ์ด ์–ด๋Š ์ •๋„ ์„œ๋กœ๋ฅผ ์ง€๋‚˜์ณ ๋งํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋Œ€๋ฐฉ์ด "์‹ค์ œ" ์˜ˆ๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์—†๋„๋ก ์‹ค์ œ ์•ฑ์„ ๋งŒ๋“ค์ž๋Š” Hixie์˜ ์ œ์•ˆ์„ ์ง€์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ œ์‹œ๋˜์ง€ ์•Š์•˜์œผ๋ฉฐ ์ง€์ง€์ž๋Š” ์‹ค์ œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋‹จ์ˆœํžˆ ์ƒ์ƒํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ฐ˜์€ ์ƒ์šฉ๊ตฌ๋กœ ๋˜์–ด ์žˆ๋Š” 100์ค„์งœ๋ฆฌ ํด๋ž˜์Šค๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ ์–ด๋ฆฌ์„์€ ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ๋‚ด๊ฐ€ ์—ฌ๊ธฐ์„œ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฝ”์–ด๊ฐ€ ์•„๋ฌด๋ฆฌ ํฌ๋”๋ผ๋„ ์—ฌ๋Ÿฌ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋งŽ์€ ์†Œ์Œ์œผ๋กœ ์ธํ•ด ๋‚œ๋…ํ™”๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ด์œ ๋Š” ๋Œ€๊ทœ๋ชจ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ์Šค์บ” ๊ฐ€๋Šฅ์„ฑ, ๊ฐ€๋…์„ฑ ๋ฐ ์œ ์ง€ ๊ด€๋ฆฌ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋นŒ๋”์—์„œ ์“ฐ๋Š” ๊ฒƒ์€ ์ค‘๊ด„ํ˜ธ ์ง€์˜ฅ์— ๋น ์ง€๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์‚ฐ์„ฑ์„ ์žƒ๊ฒŒ ๋˜์ง€๋งŒ ์ค„์„ ์“ฐ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๊ฒŒ์‹œ๋ฌผ์—์„œ "ํ•ต์‹ฌ"์„ ๊ฐ€๋ฆฌ๋Š” ์ƒ์šฉ๊ตฌ ์˜ˆ์ œ๋ฅผ โ€‹โ€‹๊ฒŒ์‹œํ–ˆ์ง€๋งŒ ์ด์ œ ํ•ต์‹ฌ์ด ์ˆ˜๋ฐฑ ์ค„์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ๋งํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋ž˜์„œ ์‹ค์ œ๋กœ, ์ƒ์šฉ๊ตฌ๋Š” ์ฝ”์–ด์— ๋น„ํ•ด ๋ฏธ๋ฏธํ• ๊นŒ์š”? ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
๋‹น์‹ ์€ ๋Š์ž„์—†์ด ๋‹น์‹ ์˜ ์ฃผ์žฅ์„ ๋ฐ”๊พธ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ์ด ๋ฌธ์ œ๋Š” ์ƒ์šฉ๊ตฌ์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ฐ€๋…์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
100์ค„์ด๋ฉด ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค.
์ค‘์š”ํ•œ ๊ฒƒ์€ ์ด ๋ผ์ธ์ด ์–ผ๋งˆ๋‚˜ ์ฝ๊ธฐ/์œ ์ง€/์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ๊ฐ€์ž…๋‹ˆ๋‹ค.

๋…ผ์Ÿ์ด ์ƒ์šฉ๊ตฌ์— ๋Œ€ํ•œ ๊ฒƒ์ธ๋ฐ๋„ ์ถฉ๋ถ„ํžˆ ๋™๋“ฑํ•œ ํ‘œํ˜„ ๋ฐฉ์‹์„ ์ œ๊ณตํ•˜๋Š” ์‚ฌ์šฉ์ž์ธ ๋‚ด๊ฐ€ ์™œ ๊ทธ๋Ÿฐ ์ƒ์šฉ๊ตฌ๋ฅผ ์šฉ์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์ถ”์ƒํ™”๋ฅผ ๋งŒ๋“ค๊ณ  ์ž‘์—…์„ ์ž๋™ํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ํด๋ž˜์Šค์™€ ํŒŒ์ผ์—์„œ ๋™์ผํ•œ ์ž‘์—…์„ ๋ฐ˜๋ณตํ•ด์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ์š”์ ์„ ์‹ค์ œ๋กœ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ์‹ค์ œ ์˜ˆ๊ฐ€ ํ•„์š”ํ•˜์‹ญ๋‹ˆ๊นŒ?
https://github.com/gskinnerTeam/flutter_vignettes

ํ™•์‹คํžˆ, ๋‹น์‹ ์€ ๋‚ด๊ฐ€ ๋‹น์‹ ์˜ ์ „์ฒด ํ”„๋กœ์ ํŠธ๋ฅผ ํŒŒํ—ค์น  ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ •ํ™•ํžˆ ์–ด๋–ค ํŒŒ์ผ์„ ๋ด์•ผ ํ•˜๋‚˜์š”?

์ž„์˜์˜ ๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์€ ์˜ˆ์ œ๋ฅผ ๋‚œ๋…ํ™”ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ •๋ฐ˜๋Œ€์ž…๋‹ˆ๋‹ค. ๊ธฐ์กด ์†”๋ฃจ์…˜์œผ๋กœ๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋Š” ์ž„์˜์˜ ๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด ๊ทธ ์˜ˆ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Hixie๊ฐ€ ๊ณ„์†ํ•ด์„œ ๋ฌป๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

gif๋ฅผ ์Šค์บ”ํ•˜๊ณ  ๊ทธ ์ค‘ ์ผ๋ถ€๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ์ƒํ•˜๊ธฐ ์‹œ์ž‘ํ•˜์‹ญ์‹œ์˜ค. ๊ทธ ์ €์žฅ์†Œ๋Š” ์‹ค์ œ๋กœ 17๊ฐœ์˜ ๋…๋ฆฝ ์‹คํ–‰ํ˜• ์•ฑ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ฆ๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด๊ฐ€ ์ž„์˜์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ž‘์„ฑํ•  ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค. ์ €๋Š” Flash๋ฅผ ์‹œ์ž‘์œผ๋กœ 20๋…„ ๋™์•ˆ ๊ทธ๊ฒƒ๋“ค์„ ๊ตฌ์ถ•ํ•ด ์™”์Šต๋‹ˆ๋‹ค. ์–ด์จŒ๋“  ์• ๋‹ˆ๋ฉ”์ด์…˜์—๋งŒ ๊ตญํ•œ๋œ ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ ๋” ํฐ ์š”์ ์„ ์„ค๋ช…ํ•˜๋Š” ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๊ฐ€์žฅ ์นœ์ˆ™ํ•œ API์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

์•„์‹œ๋‹ค์‹œํ”ผ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งค๋ฒˆ ํ•ด์•ผ ํ•˜๋Š” 6๊ฐ€์ง€๊ฐ€ ์žˆ์ง€๋งŒ ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ๋„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค?? ์ข‹์•„, ์ด์ œ ๋งค๋ฒˆ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” 6๋‹จ๊ณ„๊ฐ€ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์œผ๋กœ ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  2๊ณณ์—์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜๋Š” 3๊ฐœ๋ฅผ ๋™์‹œ์— ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ํ‘œ๋ฉด์ƒ์˜ ๋ฌธ์ œ๊ฐ€ ๋„ˆ๋ฌด ๋ถ„๋ช…ํ•ด์„œ, ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ๋ฌด์—‡์„ ๋” ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์„์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์ถ”์ƒํ™”๋ฅผ ๋งŒ๋“ค๊ณ  ์ž‘์—…์„ ์ž๋™ํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ํด๋ž˜์Šค์™€ ํŒŒ์ผ์—์„œ ๋™์ผํ•œ ์ž‘์—…์„ ๋ฐ˜๋ณตํ•ด์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ์š”์ ์„ ์‹ค์ œ๋กœ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

__๋ชจ๋‘__? ๋”ฐ๋ผ์„œ ์„ฑ๋Šฅ, ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๊นŒ?

๋…ธ๋™์„ "์ž๋™ํ™”"ํ•˜๋Š” ๊ฒƒ๊ณผ ๋…ธ๋™์„ "ํ•˜๋Š” ๊ฒƒ"์ด โ€‹โ€‹๋™์ผํ•œ ์‹œ์ ์ด ์˜ต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„, ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ๋งŒ๋“ค ์‹œ๊ฐ„์ด๋‚˜ ์˜ํ–ฅ์ด ์—†์–ด๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์ œ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์—†๋‹ค๋ฉด ์‚ฌ๋žŒ๋“ค์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋„ ๋งˆ์„ธ์š”( ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์˜ˆ์ œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋” ๋งŽ์€ ์ž‘์—…์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ์žˆ๋Š” ๋ˆ„๊ตฌ๋„ ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ์œ„ํ•ด ๋ฌด์—‡์„ ํ•ด์ค„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์„œ๋กœ๋ฅผ ๋„์šฐ๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๋Š” ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.

@TimWhiting https://github.com/TimWhiting/local_widget_state_approaches ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์— ๋ผ์ด์„ ์Šค ํŒŒ์ผ์„ ๋„ฃ์–ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์–ด๋–ค ์‚ฌ๋žŒ๋“ค์€ ํ•ด๋‹น ๋ผ์ด์„ ์Šค(BSD, MIT ๋˜๋Š” ์ด์ƒ์ ์œผ๋กœ๋Š” ์œ ์‚ฌ) ์—†์ด๋Š” ๊ธฐ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋™์ผํ•œ ๊ฒƒ์„ ํ‘œํ˜„ํ•˜๋Š” ์ถฉ๋ถ„ํžˆ ๋™๋“ฑํ•œ ๋ฐฉ๋ฒ•์ด ์ฃผ์–ด์ง€๋ฉด ์‚ฌ์šฉ์ž์ธ ๋‚ด๊ฐ€ ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ๊ทธ๋Ÿฌํ•œ ์ƒ์šฉ๊ตฌ๋ฅผ ์šฉ์ธํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์˜ˆ, ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์„ฑ๋Šฅ์€ ๋ฌผ๋ก  ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋™๋“ฑํ•œ ์†”๋ฃจ์…˜์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ƒ์šฉ๊ตฌ๊ฐ€ ์ ๊ณ  ์ฝ๊ธฐ ์‰ฝ๊ณ  ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ ๋“ฑ์˜ ์†”๋ฃจ์…˜์„ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํ›„ํฌ์˜ ์„ฑ๋Šฅ์„ ์ธก์ •ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ํ›„ํฌ๊ฐ€ ๋‹ต์ด๋ผ๋Š” ๋ง์€ ์•„๋‹ˆ์ง€๋งŒ ๊ฒฝํ—˜์ƒ ํ›„ํฌ๋ฅผ ์œ ์ง€ ๊ด€๋ฆฌํ•˜๊ธฐ๊ฐ€ ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค. ํ›„ํฌ์™€ ๊ฐ™์€ ๊ตฌ์กฐ๊ฐ€ Flutter ์ฝ”์–ด์— ์‚ฝ์ž…๋œ ๊ฒฝ์šฐ ์ž‘์—…์— ์–ด๋–ค ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์ฃผ์žฅ์— ๋Œ€ํ•ด ์—ฌ์ „ํžˆ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

gif๋ฅผ ์Šค์บ”ํ•˜๊ณ  ๊ทธ ์ค‘ ์ผ๋ถ€๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ์ƒํ•˜๊ธฐ ์‹œ์ž‘ํ•˜์‹ญ์‹œ์˜ค.

gif๋ฅผ ์Šค์บ”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋นŒ๋” ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋งŽ์€ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋„ˆ๋ฌด ๋ณต์žกํ•ด์„œ ๋” ๋†’์€ ์ˆ˜์ค€์˜ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜๋‹ค๋ฉด ์•„๋งˆ๋„ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์–ด์จŒ๋“  ์ด ํ† ๋ก ์€ ๊ฐœ์ธ์ ์ธ ์˜๊ฒฌ ์ฐจ์ด๊ฐ€ ๋” ๋งŽ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋‹น๋ฉดํ•œ ์ฃผ์š” ์ž‘์—…์— ์ง‘์ค‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์•ž์—์„œ ๋งํ–ˆ๋“ฏ์ด ์ƒ๋Œ€๊ฐ€ ์ œ๊ธฐ๋œ ๋ฌธ์ œ๋ฅผ ์ง„์ •์œผ๋กœ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฐœ์„ ์ฑ…์„ ์ฐพ์„ ๊ฒฝ์šฐ ํ›„ํฌ ์ง€์ง€์ž๋“ค์ด ์–ด๋–ป๊ฒŒ ๋” ์ž‘์€ ์˜ˆ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ @TimWhiting ์˜ ์ €์žฅ์†Œ์— ๊ธฐ์—ฌํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ์กด ์†”๋ฃจ์…˜์œผ๋กœ๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋Š” ์ž„์˜์˜ ๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด ๊ทธ ์˜ˆ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Hixie๊ฐ€ ๊ณ„์†ํ•ด์„œ ๋ฌป๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜๋‚  ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ๊ฒƒ์˜ ์˜ˆ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์€ ์ด ๋ฌธ์ œ์˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚ฉ๋‹ˆ๋‹ค.
์ด ๋ฌธ์ œ๋Š” ์˜ค๋Š˜๋‚  ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ์ผ๋ถ€๋ฅผ ์ฐจ๋‹จ ํ•ด์ œํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ด๋ฏธ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์˜ ๊ตฌ๋ฌธ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜๋‚  ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ๊ฒƒ์„ ์ œ๊ณตํ•˜๋ผ๋Š” ์š”์ฒญ์€ ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚ฌ์Šต๋‹ˆ๋‹ค.

@TimWhiting https://github.com/TimWhiting/local_widget_state_approaches ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์— ๋ผ์ด์„ ์Šค ํŒŒ์ผ์„ ๋„ฃ์–ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์–ด๋–ค ์‚ฌ๋žŒ๋“ค์€ ํ•ด๋‹น ๋ผ์ด์„ ์Šค(BSD, MIT ๋˜๋Š” ์ด์ƒ์ ์œผ๋กœ๋Š” ์œ ์‚ฌ) ์—†์ด๋Š” ๊ธฐ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์™„๋ฃŒ. ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ์— ๋Œ€ํ•ด ์ž‘์—…ํ•  ์‹œ๊ฐ„์ด ๋งŽ์ง€ ์•Š์•˜์ง€๋งŒ ์ด๋ฒˆ ์ฃผ์— ์ž‘์—…์— ๋“ค์–ด๊ฐˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ธฐ์กด ์†”๋ฃจ์…˜์œผ๋กœ๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋Š” ์ž„์˜์˜ ๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด ๊ทธ ์˜ˆ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Hixie๊ฐ€ ๊ณ„์†ํ•ด์„œ ๋ฌป๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜๋‚  ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ๊ฒƒ์˜ ์˜ˆ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์€ ์ด ๋ฌธ์ œ์˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚ฉ๋‹ˆ๋‹ค.
์ด ๋ฌธ์ œ๋Š” ์˜ค๋Š˜๋‚  ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ์ผ๋ถ€๋ฅผ ์ฐจ๋‹จ ํ•ด์ œํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ด๋ฏธ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์˜ ๊ตฌ๋ฌธ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜๋‚  ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ๊ฒƒ์„ ์ œ๊ณตํ•˜๋ผ๋Š” ์š”์ฒญ์€ ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚ฌ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งํ•œ ๊ฒƒ์„ ๋‹ค์‹œ ๋งํ•ด๋ณด์ž.

์ž‘์„ฑํ•˜๊ธฐ ์–ด๋ ต๊ณ  ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์œผ๋ฉด์„œ ํฌ๊ฒŒ ๊ฐœ์„ ๋  ์ˆ˜ ์žˆ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜, ์ƒํƒœ ๋“ฑ ์„ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด ๊ทธ ์˜ˆ๊ฐ€ ๋  ๊ฒƒ์ด๋ฉฐ, ์ด๊ฒƒ์ด Hixie๊ฐ€ ๊ณ„์† ๋ฌป๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋” ์ ์€ ์ƒ์šฉ๊ตฌ, ๋” ๋งŽ์€ ์žฌ์‚ฌ์šฉ์„ฑ, ๋” ๋งŽ์€ ๋งˆ๋ฒ•์— ๋Œ€ํ•œ ์š”๊ตฌ๋ฅผ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋„ ์ ์€ ์–‘์˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜๊ณ , ๋” ๋งŽ์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์–ธ์–ด/ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ƒ๋‹นํžˆ ๋จน์Œ์ง์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.
์ง€๊ธˆ๊นŒ์ง€ ์—ฌ๊ธฐ์— ์ œ์‹œ๋œ ์˜ˆ์ œ/์†”๋ฃจ์…˜ ์ฝค๋ณด๋Š” ์ฝ”๋“œ๋ฅผ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์ฝ”๋“œ ์ค„์„ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š”์ง€ ๊ทธ ์ด์ƒ์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„, ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ๋งŒ๋“ค ์‹œ๊ฐ„์ด๋‚˜ ์˜ํ–ฅ์ด ์—†์–ด๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์ œ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์—†๋‹ค๋ฉด ์‚ฌ๋žŒ๋“ค์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋„ ๋งˆ์„ธ์š”( ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์˜ˆ์ œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋” ๋งŽ์€ ์ž‘์—…์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ์žˆ๋Š” ๋ˆ„๊ตฌ๋„ ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ์œ„ํ•ด ๋ฌด์—‡์„ ํ•ด์ค„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์„œ๋กœ๋ฅผ ๋„์šฐ๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๋Š” ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.

@TimWhiting https://github.com/TimWhiting/local_widget_state_approaches ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์— ๋ผ์ด์„ ์Šค ํŒŒ์ผ์„ ๋„ฃ์–ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์–ด๋–ค ์‚ฌ๋žŒ๋“ค์€ ํ•ด๋‹น ๋ผ์ด์„ ์Šค(BSD, MIT ๋˜๋Š” ์ด์ƒ์ ์œผ๋กœ๋Š” ์œ ์‚ฌ) ์—†์ด๋Š” ๊ธฐ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ €๋Š” ์ด๋Ÿฌํ•œ ๋‹ค์–‘ํ•œ ์˜ˆ์ œ์™€ ์ฝ”๋“œ ์กฐ๊ฐ์„ ๋งŒ๋“œ๋Š” ๋ฐ ์•ฝ 6์‹œ๊ฐ„์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๋‹จ์ง€ ๊ทธ๊ฒƒ์ด ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ฆ๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๊ตฌ์ฒด์ ์ธ ์˜ˆ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์€ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์š”์ฒญ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๊ฒƒ์„ AnimatedContainer์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์œผ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Container(margin: EdgeInsets.symmetric(vertical: value2 * 20, horizontal: value3 * 30), color: Colors.red.withOpacity(value1));

์ด๊ฒƒ์€ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๊ฑฐ์˜ ์˜๋„์ ์œผ๋กœ ๋‘”๊ฐํ•  ์ •๋„๋กœ ์‚ฌ์†Œํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐœ์˜ ํŽ„์Šค ๋ฒ„ํŠผ, ์›€์ง์ด๋Š” ์ž…์ž, ํฌ๊ธฐ ์กฐ์ • ์ค‘์— ํŽ˜์ด๋“œ ์ธ๋˜๋Š” ํ…์ŠคํŠธ ํ•„๋“œ ๋˜๋Š” ๋’ค์ง‘ํžˆ๋Š” ์นด๋“œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•˜๋Š” ๊ฒƒ์ด ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ต์Šต๋‹ˆ๊นŒ? 15๊ฐœ์˜ ๋…๋ฆฝ๋œ ๋ง‰๋Œ€๊ฐ€ ์žˆ๋Š” ์‚ฌ์šด๋“œ๋ฐ”๋ฅผ ๋งŒ๋“ค๊ณ  ์žˆ๊ฑฐ๋‚˜ ๋ฉ”๋‰ด๋ฅผ ๋ฐ€์–ด๋„ฃ๊ณ  ์žˆ์ง€๋งŒ ๊ฐœ๋ณ„ ํ•ญ๋ชฉ์„ ๋‹ค์‹œ ๋ฐ€์–ด๋‚ด๋Š” ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ณ„์†ํ•ด์„œ, ๊ณ„์†ํ•ด์„œ. ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ์• ๋‹ˆ๋ฉ”์ด์…˜๋งŒ์„ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์œ„์ ฏ ์ปจํ…์ŠคํŠธ์—์„œ ๋ถ€๋‹ด์ด ๋˜๋Š” ๋ชจ๋“  ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‘ ๋นŒ๋”์™€ ๊ธฐ๋ณธ ์ƒํƒœ ์žฌ์‚ฌ์šฉ ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ›Œ๋ฅญํ•œ ํ‘œ์ค€ ์‚ฌ๋ก€๋ฅผ ์ œ๊ณตํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
https://github.com/flutter/flutter/issues/51752#issuecomment -671566814
https://github.com/flutter/flutter/issues/51752#issuecomment -671489384

1000๊ฐœ ์ด์ƒ์˜ ํด๋ž˜์Šค ํŒŒ์ผ๋กœ ๊ตฌ์„ฑ๋œ ํ”„๋กœ์ ํŠธ์— ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ํผ์ ธ ์žˆ๋Š” ์ด๋Ÿฌํ•œ ์ธ์Šคํ„ด์Šค ์ค‘ ๋งŽ์€ ๊ฒƒ์„ ์ƒ์ƒํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํ”ผํ•˜๋ ค๊ณ  ํ•˜๋Š” ๊ฐ€๋…์„ฑ ๋ฐ ์œ ์ง€ ๊ด€๋ฆฌ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์™„๋ฒฝํ•œ ๊ทธ๋ฆผ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์ฒฉ์ด ์ฝ”๋“œ๋ฅผ ์ฝ๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” @esDotDev๊ฐ€ ์ œ๊ณตํ•œ ์˜ˆ์ œ ์ด๋ฏธ์ง€๋Š” ์•Š์Šต๋‹ˆ๊นŒ ? ๊ทธ๋“ค์—๊ฒŒ ๋ถ€์กฑํ•œ ๊ฒƒ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์„ฑ๋Šฅ ๋ฉ”ํŠธ๋ฆญ์ด ์—†๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ง€๋งŒ @rrousselGit ์€ ๋นŒ๋”๋ณด๋‹ค ์„ฑ๋Šฅ์ด

@esDotDev ๋‚ด ์ƒ๊ฐ์— ํ•ต์‹ฌ์€ ๋ชจ๋“  ์ˆ˜๋ช… ์ฃผ๊ธฐ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์„ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋Š” ๋‹จ์ผ ํ‘œ์ค€ ์˜ˆ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(ํ›„ํฌ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ฏธ๋ž˜์˜ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜๋„ ๊ฐ€๋Šฅ). TodoMVC์™€ ๋™์ผํ•œ ์›์น™์ž…๋‹ˆ๋‹ค. React, Vue, Svelte ๋“ฑ์˜ ๋‹ค์–‘ํ•œ ๊ตฌํ˜„์„ ๊ฐ€๋ฆฌํ‚ฌ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ฐจ์ด์ ์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ๋ชจ๋‘ ๋™์ผํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌํ˜„ํ•˜๊ธฐ๋ฅผ ์›ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋น„๊ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์˜๋ฏธ๊ฐ€ ์žˆ์ง€๋งŒ ํ•œ ํŽ˜์ด์ง€๋ณด๋‹ค ๋” ์ปค์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์ผ๋ฐ˜์ ์ด๊ณ  ๋งŽ์€ ์ƒ์šฉ๊ตฌ๋ฅผ ํ•„์š”๋กœ ํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ๊ณ  ํ˜„์žฌ ์ข‹์€ ์†”๋ฃจ์…˜์ด ์—†๋Š” ์™„๋ฒฝํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์˜๋ฏธ๊ฐ€ ์—†๋‹ค๋ฉด ์‚ฌ๋žŒ๋“ค์ด ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์–ด๋–ป๊ฒŒ ๋ณต์žกํ•  ์ˆ˜ ์žˆ๋Š”์ง€์กฐ์ฐจ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ๋งํ•  ๊ฒƒ์ด๋ผ๋ฉด ๋ถ„๋ช…ํžˆ ๋ชจ๋“  ์œ ์Šค ์ผ€์ด์Šค๋Š” ์•„ํ‚คํ…์ฒ˜ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ์œ ์Šค ์ผ€์ด์Šค์˜ ์ปจํ…์ŠคํŠธ์— ๋Œ€ํ•ด ๋ฌด๋„ˆ์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์„ค๋ช…ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๋ฌผ๋ก  @TimWhiting ์˜ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—๋Š” ์™„์ „ํ•œ ์•ฑ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์†”๋ฃจ์…˜์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ํ•ด๋‹น ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ๋Œ€ํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ํ‘œ์ค€ ์˜ˆ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ทธ๊ฒƒ์ด ์ž‘๋™ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋˜ํ•œ ์šฐ๋ฆฌ๊ฐ€ ๊ฑฐ๋Œ€ํ•œ ์•ฑ์ด๋‚˜ ๋‹ค๋ฅธ ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์ง€๋งŒ TodoMVC์™€ ์œ ์‚ฌํ•œ ๋ณต์žก์„ฑ์ด ์ถฉ๋ถ„ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ƒ๋Œ€๋ฐฉ์ด "์ด๋Ÿฐ ์‹์œผ๋กœ ๋” ์ž˜ํ•  ์ˆ˜ ์žˆ๋‹ค"๊ณ  ๋งํ•  ์ˆ˜ ์—†์„ ์ •๋„๋กœ ์ถฉ๋ถ„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@Hixie ์‹ค์ œ ์•ฑ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋น„๊ตํ•˜๋„๋ก ์š”์ฒญํ•˜๋Š” ๋ฐ ๊ฒฐํ•จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‘ ๊ฐ€์ง€ ๊ฒฐํ•จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์šฐ๋ฆฌ๋Š” ์•„์ง ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ˆ„๋ฝ๋œ ๋ถ€ํ’ˆ์ด ์žˆ์œผ๋ฏ€๋กœ ์‹ค์ œ ์ƒ์‚ฐ ์กฐ๊ฑด์—์„œ ์˜ˆ์ œ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ž‘์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

final snapshot = keyword StreamBuilder();

๊ตฌํ˜„๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

POC์™€ ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ๋„ ํŒ๋‹จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์˜ค์šฉ์ด ์žˆ์„ ๋•Œ ์˜ค๋ฅ˜๋ฅผ ์ง€์ ํ•˜๋Š” ์ปดํŒŒ์ผ๋Ÿฌ ํ†ตํ•ฉ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— "ํ›„ํฌ๋ฅผ ์กฐ๊ฑด๋ถ€๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค"์™€ ๊ฐ™์€ ํ•ญ๋ชฉ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด์ง€ ์—ฌ๋ถ€๋ฅผ ํ‰๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋””์ž์ธ์˜ ์„ฑ๋Šฅ์„ ํŒ๋‹จํ•˜๊ณ , API ์‚ฌ์šฉ์„ฑ์„ ํ‰๊ฐ€ํ•˜๊ณ , ๊ตฌํ˜„ํ•˜๊ธฐ ์ „์— ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ... ๋ชจ๋‘ API ๋””์ž์ธ์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. ๋‚ด ์ง์žฅ์— ์˜ค์‹  ๊ฒƒ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. :-) (Flutter ์ƒ์‹: ์šฐ๋ฆฌ๊ฐ€ dart:ui๋ฅผ ๋งŒ๋“ค๊ธฐ ์ „์— RenderObject์™€ RenderBox et al์˜ ์ฒ˜์Œ ๋ช‡ ์ฒœ ๋ผ์ธ์ด ๊ตฌํ˜„๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ๊ณ„์…จ์Šต๋‹ˆ๊นŒ?)

๊ทธ๊ฒƒ์€ ๋‹น์‹ ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒƒ์„ ์š”๊ตฌํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ฐ”๊พธ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ์ œ์•ˆ๋œ ์ผ๋ถ€๋Š” ์–ธ์–ด ๋˜๋Š” ๋ถ„์„๊ธฐ์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์–ธ์–ด๊ฐ€ ํ•ญ์ƒ API ๋””์ž์ธ์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ๋„ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๊ฑฐ๋‚˜ Flutter๊ฐ€ ๋‹ค๋ฅธ ์–ธ์–ด๋ณด๋‹ค API ๋””์ž์ธ์— ์žˆ์–ด ์••๋„์ ์ธ ์ฐจ์ด์ ์ด๋‚˜ ์–ด๋ ค์›€์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ปดํŒŒ์ผ๋Ÿฌ ๋˜๋Š” ๋ถ„์„๊ธฐ ์ง€์› ์—†์ด ์ˆ˜ํ–‰ํ•˜๋ฉฐ ๊ฐœ๋… ์ฆ๋ช…์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” 3๊ฐœ์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ž˜ ํ™œ์šฉํ•˜๋Š” '๋ณต์žกํ•œ' ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ๋‚˜๋ฆฌ์˜ค์˜ ์˜ˆ๋ฅผ ๋งŒ๋“ค์—ˆ์œผ๋ฉฐ, ์ƒ์šฉ๊ตฌ์™€ ์—‰ํ„ฐ๋ฆฌ๋กœ ์ƒ๋‹นํžˆ ๋กœ๋“œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•œ ๊ฒƒ์€ ์‹œ์ž‘ ์œ„์น˜๋กœ ํ•˜๋“œ ์Šค๋ƒ… ๋ฐฑ(๋ชจ๋“  ์•”์‹œ์  ์œ„์ ฏ ์ œ๊ฑฐ)์ด ํ•„์š”ํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋‚˜ z์ถ•์˜ ํšŒ์ „, ๋‹จ์ผ ์ถ•์˜ ํฌ๊ธฐ ์กฐ์ • ๋˜๋Š” IW์—์„œ ๋‹ค๋ฃจ์ง€ ์•Š๋Š” ๋‹ค๋ฅธ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ํ•„์š”ํ•œ ๋ชจ๋“  ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ๋“ค์ด ์‹ฌ๊ฐํ•˜๊ฒŒ ๋ฐ›์•„๋“ค์—ฌ์ง€์ง€ ์•Š์„๊นŒ๋ด(๋‚ด ๋””์ž์ด๋„ˆ๋“ค์ด ํ•˜๋ฃจ ์ข…์ผ ์ด ๋ฌผ๊ฑด์„ ๋‚˜์—๊ฒŒ ๊ฑด๋„ค์ค„ ๊ฒƒ์ด์ง€๋งŒ) ๊ทธ๋ž˜์„œ ๋” 'ํ˜„์‹ค์ ์ธ ์„ธ๊ณ„'๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ ๊ฐ„๋‹จํ•œ ๋น„๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์Šฌ๋ผ์ด๋“œ๋ฅผ ์—ด๊ณ  ๋‹ซ์„ ์ˆ˜ ์žˆ๋Š” 3๊ฐœ์˜ ํŒจ๋„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ณ„ ์ƒํƒœ๊ฐ€ ์žˆ๋Š” 3๊ฐœ์˜ ์• ๋‹ˆ๋ฉ”์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” AnimatorController์˜ ์ „์ฒด ์ œ์–ด๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. TweenAnimationBuilder๋Š” ๊ดœ์ฐฎ์ง€๋งŒ ํŠธ๋ฆฌ์— ์ค‘์ฒฉ๋˜๋Š” ๊ฒฐ๊ณผ๋Š” ๋งค์šฐ ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํŒจ๋„์ด ์„œ๋กœ ๊ฐ’์— ์ข…์†๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— TAB๋ฅผ ํŠธ๋ฆฌ ์•„๋ž˜์— ์ค‘์ฒฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. AnimatedContainer๋Š” ๊ฐ ํŒจ๋„์ด ํ™”๋ฉด์—์„œ ๋ฏธ๋„๋Ÿฌ์ ธ์•ผ ํ•˜๊ณ  "๋ˆŒ๋Ÿฌ๋ถ™์ง€" ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์—๋Š” ์˜ต์…˜์ด ์—†์Šต๋‹ˆ๋‹ค.
https://i.imgur.com/BW6M3uM.gif
image

class _SlidingPanelViewState extends State<SlidingPanelView> with TickerProviderStateMixin {
  AnimationController leftMenuAnim;
  AnimationController btmMenuAnim;
  AnimationController rightMenuAnim;

  <strong i="12">@override</strong>
  void initState() {
    // Here I have to pass vsync to AnimationController, so I have to include a SingleTickerProviderMixin and somewhat magically pass 'this' as vsync.
    leftMenuAnim = AnimationController(duration: widget.slideDuration, vsync: this);
    btmMenuAnim = AnimationController(duration: widget.slideDuration, vsync: this);
    rightMenuAnim = AnimationController(duration: widget.slideDuration, vsync: this);
    // Here I have to call forward 3 times, cause there's no way to automate this common setup behavior
    leftMenuAnim.forward();
    btmMenuAnim.forward();
    rightMenuAnim.forward();
    // Here I have to manually bind to build, cause there is encapsulate this common setup behavior
    leftMenuAnim.addListener(() => setState(() {}));
    btmMenuAnim.addListener(() => setState(() {}));
    rightMenuAnim.addListener(() => setState(() {}));
    super.initState();
  }

  // Following 2 fxn are a blind spot as far as compiler is concerned.
  // Things may, or may not be implemented correctly, no warnings, no errors.
  <strong i="13">@override</strong>
  void dispose() {
    btmMenuAnim.dispose();
    leftMenuAnim.dispose();
    rightMenuAnim.dispose();
    super.dispose();
  }

  <strong i="14">@override</strong>
  void didUpdateWidget(SlidingPanelView oldWidget) {
    if (leftMenuAnim.duration != widget.slideDuration) {
      leftMenuAnim.duration = widget.slideDuration;
      btmMenuAnim.duration = widget.slideDuration;
      rightMenuAnim.duration = widget.slideDuration;
    }
    super.didUpdateWidget(oldWidget);
  }

  // End error-prone blind spot without a single line of unique code
  // ~50 lines in we can start to see some unique code

  void _toggleMenu(AnimationController anim) {
    bool isOpen = anim.status == AnimationStatus.forward || anim.value == 1;
    isOpen ? anim.reverse() : anim.forward();
  }

  <strong i="15">@override</strong>
  Widget build(BuildContext context) {
    double leftPanelSize = 320;
    double leftPanelPos = -leftPanelSize * (1 - leftMenuAnim.value);
    double rightPanelSize = 230;
    double rightPanelPos = -rightPanelSize * (1 - rightMenuAnim.value);
    double bottomPanelSize = 80;
    double bottomPanelPos = -bottomPanelSize * (1 - btmMenuAnim.value);
    return Stack(
      children: [
        //Bg
        Container(color: Colors.white),
        //Content Panel
        Positioned(
          top: 0,
          left: leftPanelPos + leftPanelSize,
          bottom: bottomPanelPos + bottomPanelSize,
          right: rightPanelPos + rightPanelSize,
          child: ChannelInfoView(),
        ),
        //Left Panel
        Positioned(
          top: 0,
          left: leftPanelPos,
          bottom: bottomPanelPos + bottomPanelSize,
          width: leftPanelSize,
          child: ChannelMenu(),
        ),
        //Bottom Panel
        Positioned(
          left: 0,
          right: 0,
          bottom: bottomPanelPos,
          height: bottomPanelSize,
          child: NotificationsBar(),
        ),
        //Right Panel
        Positioned(
          top: 0,
          right: rightPanelPos,
          bottom: bottomPanelPos + bottomPanelSize,
          width: rightPanelSize,
          child: SettingsMenu(),
        ),
        // Buttons
        Row(
          children: [
            Button("left", ()=>_toggleMenu(leftMenuAnim)),
            Button("btm", ()=>_toggleMenu(btmMenuAnim)),
            Button("right", ()=>_toggleMenu(rightMenuAnim)),
          ],
        )
      ],
    );
  }
}

//Demo helpers
Widget Button(String lbl, VoidCallback action) => FlatButton(child: Text(lbl), onPressed: action, color: Colors.grey);
Widget ChannelInfoView() => _buildPanel(Colors.red);
Widget ChannelMenu() => _buildPanel(Colors.pink);
Widget SettingsMenu() => _buildPanel(Colors.blue);
Widget NotificationsBar() => _buildPanel(Colors.grey);
Widget _buildPanel(Color c) => Container(color: c, child: Container(color: Colors.white.withOpacity(.5)), padding: EdgeInsets.all(10));

๋”ฐ๋ผ์„œ ํ•ด๋‹น ๋ณธ๋ฌธ์— ์žˆ๋Š” 100๊ฐœ ์ •๋„์˜ ์ค„ ์ค‘ ๋Œ€๋žต 40% ์ •๋„๋Š” ์ˆœ์ˆ˜ํ•œ ์ƒ์šฉ๊ตฌ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ ๋ˆ„๋ฝ๋˜๊ฑฐ๋‚˜ ์ž˜๋ชป ์ž…๋ ฅ๋œ ํ•ญ๋ชฉ์ด ์žˆ๋Š” 15์ค„์€ ์ฐพ๊ธฐ ํž˜๋“  ๋ฒ„๊ทธ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

StatefulProperty์™€ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ƒ์šฉ๊ตฌ๋ฅผ 15% ์ •๋„๋กœ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์•ฝ 25์ค„ ์ ˆ์•ฝ). ๊ฒฐ์ •์ ์œผ๋กœ ์ด๊ฒƒ์€ ๊ต๋ฌ˜ํ•œ ๋ฒ„๊ทธ ๋ฐ ์ค‘๋ณต ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ฌธ์ œ๋ฅผ ์™„์ „ํžˆ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ํŠนํžˆ 10ํ–‰ ํžˆํŠธ์ธ StatefulWidget์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ์ „ํžˆ ์•ฝ๊ฐ„ ์žฅํ™ฉํ•ฉ๋‹ˆ๋‹ค.

'ํ‚ค์›Œ๋“œ'์™€ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ƒ์šฉ๊ตฌ ๋ผ์ธ์„ ๋ณธ์งˆ์ ์œผ๋กœ 0%๋กœ ์ค„์ž…๋‹ˆ๋‹ค. ์ˆ˜์—…์˜ ์ „์ฒด ์ดˆ์ ์€ (๊ณ ์œ ํ•œ) ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ์‹œ๊ฐ์  ํŠธ๋ฆฌ ์š”์†Œ์— ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ StatefulWIdget์„ ํ›จ์”ฌ ๋” ๋“œ๋ฌผ๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ๋Œ€๋‹ค์ˆ˜์˜ ๋ณด๊ธฐ๊ฐ€ 10~20% ๋œ ์žฅํ™ฉํ•˜๊ณ  ๋” ์ง‘์ค‘๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์œ„์˜ ํŒจ๋„ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์‹ค์ œ ์„ธ๊ณ„์ด๋ฉฐ ์‹ค์ œ ์„ธ๊ณ„์—์„œ ๋ถ„๋ช…ํžˆ ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ์‹ค์ œ๋กœ ์ข‹์ง€ ์•Š์œผ๋ฏ€๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์œผ๋ฉฐ ์ฝ”๋“œ ๊ธฐ๋ฐ˜์—์„œ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ค‘์ฒฉ๋œ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ ๋นŒ๋”๊ฐ€ ๋ณด๊ธฐ ํ‰ํ•˜๊ฒŒ ๋ณด์ด๋ฏ€๋กœ ์‚ฌ์šฉ์ž๋„ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

IsOpen ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๊ณ  ์ž์ฒด์ ์œผ๋กœ ์—ด๋ฆฌ๊ณ  ๋‹ซํžˆ๋Š” ์ „์šฉ SlidingPanel ์œ„์ ฏ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ํŠน์ • ๋™์ž‘์ด ํ•„์š”ํ•˜๊ณ  ์ƒํƒœ ์ €์žฅ ๋…ผ๋ฆฌ๋ฅผ ์ผ๋ถ€ ์ดˆํŠน์ • ์œ„์ ฏ์œผ๋กœ ์ด๋™ํ•œ ๋‹ค์Œ ์‚ฌ์šฉํ•˜๋Š” ์ด๋Ÿฌํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ๋ชจ๋“  ๋‹จ์ผ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž์‹ ์˜ ImplicitlyAnimatedWidget์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์ž˜ ์ž‘๋™ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ์‹œ๊ฐ„๊ณผ ๋…ธ๋ ฅ์ด๋ฉฐ, ๋ง ๊ทธ๋Œ€๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์กด์žฌํ•˜๋Š” ์œ ์ผํ•œ ์ด์œ ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค(์ผ๋ฐ˜์ ์œผ๋กœ ์ƒํƒœ ์ €์žฅ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค). ์˜ˆ๋ฅผ ๋“ค์–ด Unity ๋˜๋Š” AIR์—์„œ๋Š” ๋‹จ์ผ ์ถ•์—์„œ ํŒจ๋„์„ ์ด๋™ํ•˜๊ธฐ ์œ„ํ•ด ์ „์šฉ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์—ด๊ฑฐ๋‚˜ ๋‹ซ๋Š” ์ฝ”๋“œ ํ•œ ์ค„์ด๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ „์šฉ ์œ„์ ฏ์ด ์ˆ˜ํ–‰ํ•  ์ž‘์—…์€ ์—†์Šต๋‹ˆ๋‹ค. Flutter์—์„œ๋Š” AnimatorController์˜ ๋ถ€ํŠธ์ŠคํŠธ๋ž˜ํ•‘ ๋ฐ ๋ถ„ํ•ด๋ฅผ ์บก์Šํ™”ํ•˜๋Š” ์œ ์ผํ•œ ํ•ฉ๋ฆฌ์ ์ธ ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์— Flutter์—์„œ ์ „์šฉ ์œ„์ ฏ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(TAB์œผ๋กœ ์ค‘์ฒฉ, ์ค‘์ฒฉ, ์ค‘์ฒฉํ•˜์ง€ ์•Š์œผ๋ ค๋Š” ๊ฒฝ์šฐ)

์—ฌ๊ธฐ์„œ ๋‚ด ์š”์ ์€ ์ด๋Ÿฐ ์œ ํ˜•์˜ ๊ฒƒ์ด ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ์ฐพ๊ธฐ ์–ด๋ ค์šด ์ด์œ ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋กœ์„œ ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๊ฒƒ๋“ค์ด ์šฐ๋ฆฌ ์ฝ”๋“œ๋ฒ ์ด์Šค์— ๋„ˆ๋ฌด ๋งŽ์ด ์กด์žฌํ•˜๋„๋ก ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ด์ƒ์ ์ด์ง€๋Š” ์•Š์ง€๋งŒ ํšจ๊ณผ์ ์ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๋ณผ ๋•Œ ์ด๋Ÿฌํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์ ์šฉ๋˜๊ณ  ๋ชจ๋“  ๊ฒƒ์ด ๊ดœ์ฐฎ์•„ ๋ณด์ด์ง€๋งŒ ํŒ€์ด ๋งŒ๋“ค๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ ์ˆ˜๋„ ์žˆ๊ณ  ๊ฑฐ๊ธฐ์— ๋„๋‹ฌํ•˜๋Š” ๋ฐ 20% ๋” ์˜ค๋ž˜ ๊ฑธ๋ ธ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋””๋ฒ„๊ทธํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์ด ์žˆ์ง€๋งŒ, ์ด ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋ถ„๋ช…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์™„์ „์„ฑ์„ ์œ„ํ•ด ๋นŒ๋”๋กœ ๋งŒ๋“  ๋™์ผํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ค„ ์ˆ˜๊ฐ€ ํฌ๊ฒŒ ์ค„์–ด๋“ค๊ณ  ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์—†์œผ๋ฉฐ ์™ธ๊ตญ ๊ฐœ๋…์„ ๋ฐฐ์šธ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. RE TickerProviderMixin... ํ•˜์ง€๋งŒ ์ค‘์ฒฉ์€ ์Šฌํ”ˆ ์ผ์ด๊ณ  ๋‹ค์–‘ํ•œ ๋ณ€์ˆ˜๊ฐ€ ํŠธ๋ฆฌ ์ „์ฒด์— ๋ฟŒ๋ ค์ง€๋Š” ๋ฐฉ์‹(๋™์  ์ข…๋ฃŒ ๊ฐ’, ๊ฐ’1, ๊ฐ’2 ๋“ฑ) ) ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํ•„์š” ์ด์ƒ์œผ๋กœ ์ฝ๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

```๋‹คํŠธ
ํด๋ž˜์Šค _SlidingPanelViewState ํ™•์žฅ ์ƒํƒœ{
๋ถ€์šธ isLeftMenuOpen = true;
๋ถ€์šธ isRightMenuOpen = true;
๋ถ€์šธ isBtmMenuOpen = true;

@์šฐ์„ธํ•˜๋‹ค
์œ„์ ฏ ๋นŒ๋“œ(BuildContext ์ปจํ…์ŠคํŠธ) {
TweenAnimationBuilder ๋ฐ˜ํ™˜(
ํŠธ์œˆ: ํŠธ์œˆ(์‹œ์ž‘: 0, ๋: isLeftMenuOpen ? 1: 0),
์ง€์† ์‹œ๊ฐ„: widget.slideDuration,
๋นŒ๋”: (_, leftAnimValue, __) {
TweenAnimationBuilder ๋ฐ˜ํ™˜(
ํŠธ์œˆ: ํŠธ์œˆ(์‹œ์ž‘: 0, ๋: isRightMenuOpen ? 1: 0),
์ง€์† ์‹œ๊ฐ„: widget.slideDuration,
๋นŒ๋”: (_, rightAnimValue, __) {
TweenAnimationBuilder ๋ฐ˜ํ™˜(
ํŠธ์œˆ: ํŠธ์œˆ(์‹œ์ž‘: 0, ๋: isBtmMenuOpen ? 1: 0),
์ง€์† ์‹œ๊ฐ„: widget.slideDuration,
๋นŒ๋”: (_, btmAnimValue, __) {
์ด์ค‘ leftPanelSize = 320;
์ด์ค‘ leftPanelPos = -leftPanelSize * (1 - leftAnimValue);
์ด์ค‘ rightPanelSize = 230;
๋”๋ธ” rightPanelPos = -rightPanelSize * (1 - rightAnimValue);
์ด์ค‘ bottomPanelSize = 80;
์ด์ค‘ bottomPanelPos = -bottomPanelSize * (1 - btmAnimValue);
๋ฐ˜ํ™˜ ์Šคํƒ(
์–ด๋ฆฐ์ด๋“ค: [
//๋น„์ง€
์šฉ๊ธฐ(์ƒ‰์ƒ: Colors.white),
//์ฃผ ์ฝ˜ํ…์ธ  ์˜์—ญ
ํฌ์ง€์…”๋‹(
์ƒ๋‹จ: 0,
์™ผ์ชฝ: leftPanelPos + leftPanelSize,
ํ•˜๋‹จ: bottomPanelPos + bottomPanelSize,
์˜ค๋ฅธ์ชฝ: rightPanelPos + rightPanelSize,
์ž์‹: ChannelInfoView(),
),
//์™ผ์ชฝ ํŒจ๋„
์œ„์น˜(
์ƒ๋‹จ: 0,
์™ผ์ชฝ: leftPanelPos,
ํ•˜๋‹จ: bottomPanelPos + bottomPanelSize,
๋„ˆ๋น„: leftPanelSize,
์ž์‹: ChannelMenu(),
),
//ํ•˜๋‹จ ํŒจ๋„
์œ„์น˜(
์™ผ์ชฝ: 0,
์˜ค๋ฅธ์ชฝ: 0,
ํ•˜๋‹จ: bottomPanelPos,
๋†’์ด: bottomPanelSize,
์ž์‹: NotificationsBar(),
),
//์˜ค๋ฅธ์ชฝ ํŒจ๋„
์œ„์น˜(
์ƒ๋‹จ: 0,
์˜ค๋ฅธ์ชฝ: rightPanelPos,
ํ•˜๋‹จ: bottomPanelPos + bottomPanelSize,
๋„ˆ๋น„: rightPanelSize,
์ž์‹: SettingsMenu(),
),
// ๋ฒ„ํŠผ
์—ด(
์–ด๋ฆฐ์ด๋“ค: [
๋ฒ„ํŠผ("์™ผ์ชฝ", () => setState(() => isLeftMenuOpen = !isLeftMenuOpen)),
๋ฒ„ํŠผ("btm", () => setState(() => isBtmMenuOpen = !isBtmMenuOpen)),
๋ฒ„ํŠผ("์˜ค๋ฅธ์ชฝ", () => setState(() => isRightMenuOpen = !isRightMenuOpen)),
],
)
],
);
},
);
},
);
},
);
}
}

๋งˆ์ง€๋ง‰ ๊ฒƒ์€ ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค... ์ €๋Š” ์›๋ž˜ ๋นŒ๋”๊ฐ€ ์Šคํƒ์ด ์•„๋‹Œ ์œ„์น˜ ์ง€์ • ์œ„์ ฏ ์ฃผ์œ„์— ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ œ์•ˆํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ(๊ทธ๋ฆฌ๊ณ  ์—ฌ์ „ํžˆ ์™ผ์ชฝ ๋ฐ ์˜ค๋ฅธ์ชฝ ํŒจ๋„์— ๋Œ€ํ•ด ์ œ์•ˆํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค) ๋งจ ์•„๋ž˜์— ์žˆ๋Š” ๊ฒƒ์ด ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค. ์„ธ ๊ฐ€์ง€ ๋ชจ๋‘, ๋‚˜๋Š” ๊นจ๋‹ฌ์•˜๋‹ค ๋‹น์‹ ์—๊ฒŒ ์ผ์„์ฃผ๋Š” ๋นŒ๋” child ์ธ์ˆ˜ ์‹ค์ œ๋กœ ๋‹น์‹ ์ด ์ •๋ง๋กœ ๋ชจ๋‘ ์œ ์ง€ํ•˜๊ธฐ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ถฉ๋ถ„ํ•˜์ง€ Container ์™€ Row ๋ฅผ ํ†ตํ•ด ์ผ์ •์„ ๋นŒ๋“œ. ์ฒซ ๋ฒˆ์งธ ๋นŒ๋” ์œ„์— ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋‚ด ์š”์ ์€ ์ด๋Ÿฐ ์œ ํ˜•์˜ ๊ฒƒ์ด ์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ์ฐพ๊ธฐ ์–ด๋ ค์šด ์ด์œ ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋กœ์„œ ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๊ฒƒ๋“ค์ด ์šฐ๋ฆฌ ์ฝ”๋“œ๋ฒ ์ด์Šค์— ๋„ˆ๋ฌด ๋งŽ์ด ์กด์žฌํ•˜๋„๋ก ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ด์ƒ์ ์ด์ง€๋Š” ์•Š์ง€๋งŒ ํšจ๊ณผ์ ์ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๋ณผ ๋•Œ ์ด๋Ÿฌํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์ ์šฉ๋˜๊ณ  ๋ชจ๋“  ๊ฒƒ์ด ๊ดœ์ฐฎ์•„ ๋ณด์ด์ง€๋งŒ ํŒ€์ด ๋งŒ๋“ค๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ ์ˆ˜๋„ ์žˆ๊ณ  ๊ฑฐ๊ธฐ์— ๋„๋‹ฌํ•˜๋Š” ๋ฐ 20% ๋” ์˜ค๋ž˜ ๊ฑธ๋ ธ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋””๋ฒ„๊ทธํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์ด ์žˆ์ง€๋งŒ, ์ด ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋ถ„๋ช…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ์ด๊ฒƒ์€ ์‚ฌ๊ณ ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋งค์šฐ ์˜๋„์ ์œผ๋กœ ์„ค๊ณ„๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์œ„์ ฏ์„ ์ž์ฒด ์œ„์ ฏ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์ด ์‚ฌ๋žŒ๋“ค์ด Flutter๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ๋งค์šฐ ์˜๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์œ„์—์„œ "Flutter์˜ ๋””์ž์ธ ์ฒ ํ•™์˜ ํฐ ๋ถ€๋ถ„์€ ์‚ฌ๋žŒ๋“ค์„ ์˜ฌ๋ฐ”๋ฅธ ์„ ํƒ์œผ๋กœ ์•ˆ๋‚ดํ•˜๋Š” ๊ฒƒ"์ด๋ผ๊ณ  ์–ธ๊ธ‰ํ–ˆ์„ ๋•Œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์›๋ž˜ ๋นŒ๋”๊ฐ€ ์Šคํƒ๋ณด๋‹ค๋Š” ๋ฐฐ์น˜๋œ ์œ„์ ฏ ์ฃผ์œ„์— ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ œ์•ˆํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  ๋‚˜๋Š” ์—ฌ์ „ํžˆ ์™ผ์ชฝ ๋ฐ ์˜ค๋ฅธ์ชฝ ํŒจ๋„์— ๋Œ€ํ•ด ์ œ์•ˆํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค)

๊ฐ„๊ฒฐํ•จ์„ ์œ„ํ•ด ์‹ค์ œ๋กœ ์ƒ๋žตํ–ˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ์—ฌ๊ธฐ์— Content ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ํ•„์š”ํ•˜๊ณ  3๊ฐ€์ง€ ๋ฉ”๋‰ด ๋ชจ๋‘์˜ ํฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž์ฒด ์œ„์น˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, 3๊ฐœ ๋ชจ๋‘๊ฐ€ ํŠธ๋ฆฌ์˜ ๋งจ ์œ„์— ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ๋‹ค์‹œ ๋นŒ๋“œํ•˜๋Š” ๊ฒฝ์šฐ ์ „์ฒด ๋ณด๊ธฐ๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ ์ฃผ์œ„๋ฅผ ๋Œ์•„๋‹ค๋‹ˆ์ง€ ์•Š๊ณ  ๋‹ค์‹œ ๋นŒ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ณ ์ „์ ์ธ ๋ฐ์Šคํฌํƒ‘ ์Šคํƒ€์ผ์˜ ์Šค์บํด๋“œ์ž…๋‹ˆ๋‹ค.

๋ฌผ๋ก  ์šฐ๋ฆฌ๋Š” ํŠธ๋ฆฌ๋ฅผ ๋ถ„ํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(ํ•ญ์ƒ ์„ ํƒ ์‚ฌํ•ญ). ์šฐ๋ฆฌ๋Š” ๋” ํฐ ์œ„์ ฏ์— ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ํ•œ ๋ˆˆ์— grokability๋ฅผ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์„ ๋ณธ ์ ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋…์ž๊ฐ€ ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ถ”๊ฐ€์ ์ธ ์ธ์ง€ ๋‹จ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋ฆฌํ‚ค๋‹ค. ๋‹น์‹ ์ด ๋‚˜๋ฌด๋ฅผ ์ชผ๊ฐœ๋Š” ์ˆœ๊ฐ„, ๊ฐ‘์ž๊ธฐ ๋ณ€์ˆ˜ ํ• ๋‹น์˜ ๋นต ๋ถ€์Šค๋Ÿฌ๊ธฐ ํ”์ ์„ ๋”ฐ๋ผ๊ฐ€์„œ ์—ฌ๊ธฐ์— ์ „๋‹ฌ๋˜๋Š” ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€ ํŒŒ์•…ํ•˜๊ณ  ์ „์ฒด๊ฐ€ ์–ด๋–ป๊ฒŒ ํ•จ๊ป˜ ๋“ค์–ด๋งž๋Š”์ง€ ํŒŒ์•…ํ•ฉ๋‹ˆ๋‹ค. ์†Œํ™” ๊ฐ€๋Šฅํ•œ ๋‚˜๋ฌด๋กœ ๋‚˜๋ฌด๋ฅผ ์ œ์‹œํ•˜๋Š” ๊ฒƒ์€ ํ•ญ์ƒ ๋‚ด ๊ฒฝํ—˜์—์„œ ์ถ”๋ก ํ•˜๊ธฐ๊ฐ€ ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.

์•„๋งˆ๋„ ์ „์šฉ RenderObject์— ๋Œ€ํ•œ ์ข‹์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜๋Š” ์œ„์ ฏ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” 3๊ฐœ์˜ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌ๋˜๋Š” AnimatorObjects :D

์ด๋Ÿฌํ•œ ์œ„์ ฏ์„ ์ž์ฒด ์œ„์ ฏ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ๊ตฌ์ฒดํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—: ์ด ๊ฒฝ์šฐ ์ด๊ฒƒ์€ ์Šค์บํด๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ํ•˜์œ„ ๋ณด๊ธฐ๋Š” ์ด๋ฏธ ์ž์ฒด ์œ„์ ฏ์ž…๋‹ˆ๋‹ค. ์ด ์‚ฌ๋žŒ์€ ์ž์‹ ๋ฐฐ์น˜ ๋ฐ ๋ฒˆ์—ญ๋งŒ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ž์‹์€ BottomMenu(), ChannelMenu(), SettingsView(), MainContent() ๋“ฑ์ž…๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ ์šฐ๋ฆฌ๋Š” ๋‹จ์ˆœํžˆ ์ด๋™์— ๋Œ€ํ•œ ์ƒ์šฉ๊ตฌ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ž์ฒด ํฌํ•จ๋œ ์œ„์ ฏ์˜ ๋ฌด๋ฆฌ๋ฅผ ์ž์ฒด ํฌํ•จ๋œ ์œ„์ ฏ์˜ ๋˜ ๋‹ค๋ฅธ ๋ ˆ์ด์–ด๋กœ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ์„ฑ๋Šฅ ์Šน๋ฆฌ๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ์ด ๊ฒฝ์šฐ ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ _์ƒ๊ฐํ•˜๋Š”_ ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ, ์ฆ‰ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ๋™์ผํ•œ ์„ฑ๋Šฅ์˜ ๋ทฐ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ฐ€์–ด๋ถ™์ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

[ํŽธ์ง‘] ์ด ์ปจํ…์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์ œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ „์šฉ RenderObject๋ฅผ ์ œ์•ˆํ•˜๋Š” ์ด์œ ๋Š” ๋ ˆ์ด์•„์›ƒ์„ ๋” ์ข‹๊ฒŒ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ธก๋ฉด์ด ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์— ์žˆ์„ ๊ฒƒ์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์Šคํƒ ์ˆ˜ํ•™์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  3๊ฐœ์˜ 0..1 ๋”๋ธ”(value1, value2, value3)์„ ๋ Œ๋” ๊ฐ์ฒด๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ๋Œ€๋ถ€๋ถ„ ์ด ํ† ๋ก ์˜ ๋ถ€์ˆ˜์ ์ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์‹œ์ ์—์„œ ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์—์„œ Hooks ๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ๊ฒƒ์œผ๋กœ ์ œ๊ณต๋˜๋Š” ๋‹จ์ˆœํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋” ๊ด€๋ จ์„ฑ์ด ๋†’์€ ๋ฉ”๋ชจ์—์„œ @TimWhiting ์˜ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ ๋ฐ๋ชจ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ๊ท ์—ด์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค: https://github.com/TimWhiting/local_widget_state_approaches/pull/1
Hooks ๋ฒ„์ „์€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์„ฑ๋Šฅ ํŠน์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ(๋˜๋Š” ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ; ํ˜„์žฌ ์ตœ์ ์ด ์•„๋‹Œ ๊ณณ์„ ๋ณด์—ฌ์ฃผ๋Š” ์ฃผ์„์ด ์žˆ์Œ)์„ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์„ ๋ณผ ์ˆ˜ ์žˆ์„์ง€ ํ™•์‹ ์ด ์„œ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

(๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์€ ๊ฒฝ์šฐ ์—ฌ๊ธฐ์—์„œ ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ธ์ง€ ๋˜๋Š” ์™„๋ฃŒํ•˜๊ธฐ ์ „์— ํ•ด๊ฒฐํ•ด์•ผ ํ•  ์ค‘์š”ํ•œ ์‚ฌํ•ญ์ด ๋ˆ„๋ฝ๋œ ๊ฒƒ์ธ์ง€๋„ ๋งค์šฐ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.)

์ด ์˜ˆ์—์„œ ๋ณต์› ํ•ญ๋ชฉ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๊นŒ? ๋‚˜๋Š” ๊ทธ๊ฒƒ ๋•Œ๋ฌธ์— ์–ด๋ ค์›€์„ ๊ฒช๊ณ  ์žˆ์œผ๋ฉฐ RestorationMixin์ด ๋ฌด์—‡์„ ํ•˜๋Š”์ง€์กฐ์ฐจ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ... ๋‚˜๋ฅผ ์œ„ํ•ด ์ด๊ฒƒ์„ ์ดํ•ดํ•˜๋Š” ๋ฐ ์•ฝ๊ฐ„์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” Remi๊ฐ€ 4์ดˆ ๋งŒ์— ํ›„ํฌ ๋ฒ„์ „์„ ์™„์„ฑํ•  ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. :)

StatefulHookWidget ๊ฐ€ ์•„๋‹Œ HookWidget ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณต์› API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํ˜„์žฌ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด์ƒ์ ์œผ๋กœ๋Š” ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

final value = useState(42);

์•ˆ์œผ๋กœ:

final value = useRestorableInt(42);

๊ทธ๋Ÿฌ๋‚˜ ํ˜„์žฌ ๋ณต์› API๋Š” ์‹ค์ œ๋กœ ํ›„ํฌ๋ฅผ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์•ฝ๊ฐ„์˜ ์ƒ๊ฐ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ React hooks์—๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ๋˜๋Š” "ํ•ต์‹ฌ" ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

int userId;

Future<User> user = useMemo(() => fetchUser(id), [id]);

์—ฌ๊ธฐ์„œ ์ด ์ฝ”๋“œ๋Š” "์ฝœ๋ฐฑ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜๊ณ  ๋ฐฐ์—ด ๋‚ด๋ถ€์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ฝœ๋ฐฑ์„ ๋‹ค์‹œ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค"๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

Flutter_hooks๋Š” ์ด๊ฒƒ์„ 1๋Œ€1๋กœ ๋‹ค์‹œ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ(๋‹จ์ง€ ํฌํŠธ์ผ ๋ฟ์ด๋ฏ€๋กœ) Flutter์— ์ตœ์ ํ™”๋œ ์ฝ”๋“œ์— ๋Œ€ํ•ด ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์•„๋งˆ๋„ ๋‹ค์Œ์„ ์›ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค:

int userId;

Future<User> user = useMemo1(id, (id) => fetchUser(id));

๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋ชฉ๋ก ํ• ๋‹น์„ ํ”ผํ•˜๊ณ  ๊ธฐ๋Šฅ ํ•ด์ œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

์ด ๋‹จ๊ณ„์—์„œ๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์ง€๋งŒ ์˜ˆ๋ฅผ ๋“ค์–ด flutter_hooks ๋ฅผ ์‚ฌ์šฉํ•  ๊ณ„ํš์ด๋ผ๋ฉด ์–ธ๊ธ‰ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

@Hixie ์• ๋‹ˆ๋ฉ”์ด์…˜ ์˜ˆ์ œ๋ฅผ ํ›„ํฌ๋กœ ์ด์‹ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํฅ๋ฏธ๋กœ์šด ์˜ˆ์˜€์Šต๋‹ˆ๋‹ค. ์ƒ๊ฐํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!
๊ธฐ๋ณธ์ ์œผ๋กœ "active" ๋ฐ "duration"์˜ ๊ตฌํ˜„์ด ์–ด๋””์—๋‚˜ ์žˆ๋‹ค๋Š” ์ ์—์„œ ์ข‹์€ ์˜ˆ์ž…๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ ์—์„œ ์„œ๋กœ ์˜์กดํ•จ).
์š”์ ๊นŒ์ง€ ์ˆ˜๋งŽ์€ "if (active)" / "controller.repeat" ํ˜ธ์ถœ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ๋…ผ๋ฆฌ๊ฐ€ ์„ ์–ธ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๊ณ  ์ค‘๋ณต ์—†์ด ํ•œ ๊ณณ์— ์ง‘์ค‘๋ฉ๋‹ˆ๋‹ค.

์ด ์˜ˆ์ œ๋Š” ๋˜ํ•œ ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ์บ์‹œํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ด๋Š” ExpensiveWidget์„ ๋„ˆ๋ฌด ์ž์ฃผ ์žฌ๊ตฌ์ถ•ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.
const ์ƒ์„ฑ์ž์˜ ์ด์ ์„ ์–ป์ง€๋งŒ ๋™์  ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ๋” ๋‚˜์€ ํ•ซ ๋ฆฌ๋กœ๋“œ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ๋ฐฐ๊ฒฝ์ƒ‰์˜ Timer.periodic ๊ธฐ๊ฐ„์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์ฆ‰์‹œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@rrousselGit ๋งํฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? @TimWhiting ์˜ ์ €์žฅ์†Œ์—์„œ ์ƒˆ๋กœ์šด ๊ฒƒ์„ ๋ณด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

StatefulHookWidget ๊ฐ€ ์•„๋‹Œ HookWidget ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณต์› API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํ˜„์žฌ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ค ์†”๋ฃจ์…˜์„ ์ œ์‹œํ•˜๋“ , ๋ชจ๋“  ๋งˆ์ง€๋ง‰ ๋ฏน์Šค์ธ์— ๋Œ€ํ•ด ์•Œ ํ•„์š”๊ฐ€ ์—†๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ TickerProviderStateMixin ๋˜๋Š” RestorationMixin๊ณผ ๊ฐ™์€ mixin์„ ๋„์ž…ํ•˜๋Š” ๋‹ค๋ฅธ ํŒจํ‚ค์ง€์™€ ํ•จ๊ป˜ ์šฐ๋ฆฌ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

https://github.com/TimWhiting/local_widget_state_approaches/pull/3

๋™์˜ํ•˜์ง€๋งŒ ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. useAnimationController๋Š” ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž๊ฐ€ SingleTickerProvider์— ๋Œ€ํ•ด ์‹ ๊ฒฝ ์“ธ ๊ฒƒ์„ ์š”๊ตฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

AutomaritKeepAlive๋Š” ๋™์ผํ•œ ์น˜๋ฃŒ๋กœ๋ถ€ํ„ฐ ํ˜œํƒ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋‚ด๊ฐ€ ์ƒ๊ฐํ•œ ๊ฒƒ ์ค‘ ํ•˜๋‚˜๋Š” "useKeepAlive(bool)" ํ›„ํฌ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ mixin๊ณผ "super.build(context)"๋ฅผ ๋ชจ๋‘ ํ”ผํ•ฉ๋‹ˆ๋‹ค(ํ›„์ž๋Š” ์ƒ๋‹นํžˆ ํ˜ผ๋ž€์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค)

๋˜ ๋‹ค๋ฅธ ํฅ๋ฏธ๋กœ์šด ์ ์€ ๋ฆฌํŒฉํ† ๋ง ์ค‘์— ํ•„์š”ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์›์‹œ ์ ‘๊ทผ ๋ฐฉ์‹๊ณผ ํ›„ํฌ์— ๋Œ€ํ•ด TickerMode ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ๊ฐ„์˜ ์ฐจ์ด๋ฅผ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

diff์— ๋‹ค๋ฅธ ๊ฒƒ๋“ค์ด ์„ž์—ฌ ์žˆ์ง€๋งŒ, ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‚ฌ์‹ค์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋กœ์ง์„ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋กœ ์ด๋™ํ•˜๋ ค๋ฉด StatefulWidget์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • ํ›„ํฌ ๋ณ€๊ฒฝ์€ ์ˆœ์ „ํžˆ ์ถ”๊ฐ€์ ์ž…๋‹ˆ๋‹ค. ๊ธฐ์กด ๋ผ์ธ์€ ํŽธ์ง‘/์ด๋™๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•˜๋ฉฐ ์ด ์Šคํƒ€์ผ์˜ ์ž์ฒด ํฌํ•จ๋œ ์ƒํƒœ ๊ฐœ์ฒด์—์„œ ์ค‘์š”ํ•œ ์Šน๋ฆฌ์ž…๋‹ˆ๋‹ค. ํŠธ๋ฆฌ์˜ ์ค‘์ฒฉ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์„ ๋ฆฌํŒฉํ† ๋งํ•˜๊ณ  ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ๊ทผ๋ณธ์ ์œผ๋กœ ๋” ์–ด๋ ต๊ณ  ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ”„๋กœ์ ํŠธ๊ฐ€ ์ง„ํ–‰๋˜๋Š” ๋™์•ˆ ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ์ตœ์ข… ํ’ˆ์งˆ์— ๋ณด์ด์ง€ ์•Š์ง€๋งŒ ํ™•์‹คํ•œ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.

๋™์˜!
๋˜ํ•œ ์ฝ”๋“œ ๊ฒ€ํ† ๋ฅผ ํ›จ์”ฌ ์‰ฝ๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

final value = useSomething();
+ final value2 = useSomethingElse();

return Container(
  color: value.color,
-  child: Text('${value.name}'),
+  child: Text('${value.name} $value2'),
);

๋Œ€:

return SomethingBuilder(
  builder: (context, value) {
-    return Container(
-      color: value.color,
-      child: Text('$value'),
+    return SomethingElseBuilder(
+      builder: (context, value2) {
+        return Container(
+          color: value.color,
+          child: Text('${value.name} $value2'),
+        );
+      }
    );
  },
);

๋‘ ๋ฒˆ์งธ diff์—์„œ๋Š” Container ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๊ณ  Text ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@rrousselGit ํ‚ค์›Œ๋“œ ์ง€์›์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋ณด์ผ ์ˆ˜ ์žˆ๋Š”์ง€ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฒ„์ „์„ ์‹œ๋„ํ•˜๊ณ  ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ? ์ „์šฉ 'use' ํ‚ค์›Œ๋“œ๋งŒ ์žˆ๋Š” ํ›„ํฌ์™€ ์‹ค์งˆ์ ์œผ๋กœ ์œ ์‚ฌํ•ฉ๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ๋” ์‰ฝ๊ฒŒ ๋”ฐ๋ผ๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? useEffect, useMemo ๋“ฑ๊ณผ ๊ฐ™์€ ์™ธ๊ตญ ๊ฐœ๋…์ด ๋„ˆ๋ฌด ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ํ›„ํฌ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ท ์ผํ•˜๊ฒŒ ๋น„๊ตํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์ฃผ๋ชฉํ•ด์•ผ ํ•  ๋˜ ๋‹ค๋ฅธ ์‚ฌํ•ญ์€ ์ด ๋ชจ๋“  ๊ฒƒ์ด ์‹ค์ œ๋กœ ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๊ณณ์€ ์—ฌ๋Ÿฌ ์œ„์ ฏ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ด '์ƒ‰์ƒ ์Šคํ…Œํ•‘' ๋…ผ๋ฆฌ๋ฅผ ๊ณต์œ ํ•˜๋Š” ๋ฐ ๋ชจ๋‘ ํ•„์š”ํ•˜์ง€๋งŒ ๊ฒฐ๊ณผ ์ƒ‰์ƒ์„ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ›„ํฌ ์Šคํƒ€์ผ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋…ผ๋ฆฌ๋ฅผ ๋ฌถ์–ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๊ฐ•์š”ํ•˜๋Š” ์•„ํ‚คํ…์ฒ˜ ์ฝ”๋„ˆ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ •๋ง ๋ถˆ๊ฐ€์ง€๋ก ์ ์ด๋ฉฐ ์œ ์—ฐํ•ฉ๋‹ˆ๋‹ค.

Stateful ์ ‘๊ทผ ๋ฐฉ์‹์—์„œ ์šฐ๋ฆฌ๋Š”

  • ๋…ผ๋ฆฌ ๋ณต์‚ฌ ๋ฐ ๋ถ™์—ฌ๋„ฃ๊ธฐ(์œ ์ง€ ๊ด€๋ฆฌ๊ฐ€ ๋งค์šฐ ๋ถˆ๊ฐ€๋Šฅ)
  • ๋นŒ๋” ์‚ฌ์šฉ(ํŠนํžˆ ์ค‘์ฒฉ์„ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ€๋…์„ฑ์ด ์ข‹์ง€ ์•Š์Œ)
  • ๋ฏน์‹ฑ(์ž˜ ๊ตฌ์„ฑ๋˜์ง€ ์•Š์Œ, ๊ณต์œ  ์ƒํƒœ์—์„œ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฏน์Šค์ธ์ด ์ถฉ๋Œํ•˜๊ธฐ ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค)

๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ํ•ต์‹ฌ์€ ํ›„์ž์˜ ๊ฒฝ์šฐ ์ฆ‰์‹œ ์•„ํ‚คํ…์ฒ˜ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ๋‚ด ํŠธ๋ฆฌ์˜ ์–ด๋””์— ๋„ฃ์–ด์•ผ ํ•˜๋Š”์ง€, ์ด๊ฒƒ์„ ๊ฐ€์žฅ ์ž˜ ์บก์Šํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋นŒ๋”์—ฌ์•ผ ํ•ฉ๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์‚ฌ์šฉ์ž ์ •์˜ ์œ„์ ฏ์ด์–ด์•ผ ํ• ๊นŒ์š”? ์ „์ž์˜ ๊ฒฝ์šฐ ์ด ์žฌ์‚ฌ์šฉ๋œ ๋…ผ๋ฆฌ ๋ฉ์–ด๋ฆฌ๋ฅผ ์ €์žฅํ•  ํŒŒ์ผ์ด ์œ ์ผํ•œ ๊ฒฐ์ •์ด๋ฏ€๋กœ ํŠธ๋ฆฌ์— ์ „ํ˜€ ์˜ํ–ฅ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ด๋Ÿฌํ•œ ๋กœ์ง ์บก์Šํ™” ์ค‘ ๋ช‡ ๊ฐ€์ง€๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๊ณ„์ธต ๊ตฌ์กฐ์—์„œ ์œ„์•„๋ž˜๋กœ ์ด๋™ํ•˜๊ฑฐ๋‚˜ ํ˜•์ œ ์œ„์ ฏ์œผ๋กœ ์ด๋™ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ๋“ฑ ๊ตฌ์กฐ์ ์œผ๋กœ ๋งค์šฐ ์ข‹์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ฒฐ์ฝ” ์ „๋ฌธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋…ผ๋ฆฌ ๋ฅผ

Vue.js๋ฅผ ์˜ค๋žซ๋™์•ˆ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ๋‹ค์Œ ๋ฒ„์ „์„ ์œ„ํ•œ ์ž์ฒด API(Hooks์—์„œ ์˜๊ฐ์„ ๋ฐ›์Œ)๋„ ์žˆ์œผ๋ฏ€๋กœ ํ•œ ๋ฒˆ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  CMIIW๋Š” ๋ฐ˜์‘ ํ›„ํฌ์˜ ๊ทœ์น™(์กฐ๊ฑด๋ถ€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ)์ด Composition API์— ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ทœ์น™์„ ์‹œํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋ฆฐํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋™๊ธฐ๋ถ€์—ฌ ์„น์…˜์€ ์—ฌ๊ธฐ์—์„œ OP๋ฅผ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๊ฐ•ํ™”ํ•ฉ๋‹ˆ๋‹ค.

๋™๊ธฐ ๋ถ€์—ฌ
๋ณต์žกํ•œ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ฝ”๋“œ๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๊ธฐ๋Šฅ์ด ์ฆ๊ฐ€ํ•จ์— ๋”ฐ๋ผ ์ถ”๋ก ํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํŠนํžˆ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž์‹ ์ด ์ž‘์„ฑํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ๋ฅผ ์ฝ์„ ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
[๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค] ์—ฌ๋Ÿฌ ๊ตฌ์„ฑ ์š”์†Œ ๊ฐ„์— ๋…ผ๋ฆฌ๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊นจ๋—ํ•˜๊ณ  ๋น„์šฉ์ด ๋“ค์ง€ ์•Š๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ๋ถ€์กฑํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ๋‹จ์–ด๋Š” "๊นจ๋—ํ•œ"๊ณผ "๋น„์šฉ ๋ฌด๋ฃŒ"์ž…๋‹ˆ๋‹ค. Mixin์€ ๋น„์šฉ์ด ๋“ค์ง€ ์•Š์ง€๋งŒ ๊นจ๋—ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๋นŒ๋”๋Š” ๊นจ๋—ํ•˜์ง€๋งŒ ๊ฐ€๋…์„ฑ ์ธก๋ฉด์—์„œ ๋น„์šฉ์ด ๋“ค์ง€ ์•Š์œผ๋ฉฐ, ๊ณ„์ธต ๊ตฌ์กฐ ์ธก๋ฉด์—์„œ ํŠธ๋ฆฌ๋ฅผ ์ด๋™ํ•˜๊ณ  ์ถ”๋ก ํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ์œ„์ ฏ ์•„ํ‚คํ…์ฒ˜ ์ธก๋ฉด์—์„œ ๋น„์šฉ์ด ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋˜ํ•œ ์ด๊ฒƒ์ด ๊ฐ€๋…์„ฑ ๋…ผ์˜์—์„œ ์–ธ๊ธ‰ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. "_๊ฐœ๋ฐœ์ž๊ฐ€ ์ž‘์„ฑํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ๋ฅผ ์ฝ์„ ๋•Œ ํŠนํžˆ ๋ฐœ์ƒ_". ๋ฌผ๋ก  _๋‹น์‹ ์˜_ ์ค‘์ฒฉ ๋นŒ๋”๋Š” ์ฝ๊ธฐ ์‰ฌ์šธ ์ˆ˜ ์žˆ๊ณ , ๊ฑฐ๊ธฐ์— ๋ฌด์—‡์ด ์žˆ๋Š”์ง€ ์•Œ๊ณ  ํŽธ์•ˆํ•˜๊ฒŒ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ์ฝ”๋“œ๋ฅผ ์ฝ๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๋” ํฐ ํ”„๋กœ์ ํŠธ์—์„œ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋˜๋Š” ๋ช‡ ์ฃผ/mth ์ „์˜ ์ฝ”๋“œ๋ฅผ ์ฝ๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒƒ๋“ค์„ ํŒŒ์‹ฑํ•˜๊ณ  ๋ฆฌํŒฉํ† ๋งํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ํŠนํžˆ ๊ด€๋ จ ์„น์…˜.

๋‹จ์ˆœํžˆ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ์ด์œ :

... ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„๊ณผ ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ ์กฐ๊ฐ์œผ๋กœ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ๋งŒ์œผ๋กœ๋„ ์šฐ๋ฆฌ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์œ ์—ฐ์„ฑ ์ธก๋ฉด์—์„œ ๊ฝค ๋ฉ€๋ฆฌ ๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ์˜ ์ง‘ํ•ฉ์ ์ธ ๊ฒฝํ—˜์€ ์ด๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ์„ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ •๋ง ์ปค์งˆ ๋•Œ ์ˆ˜๋ฐฑ ๊ฐœ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ƒ๊ฐํ•ด ๋ณด์‹ญ์‹œ์˜ค. ์ด๋Ÿฌํ•œ ๋Œ€๊ทœ๋ชจ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์ฝ”๋“œ ๊ณต์œ  ๋ฐ ์žฌ์‚ฌ์šฉ์ด ํŠนํžˆ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋…ผ๋ฆฌ์  ๋‹จํŽธํ™”๋ฅผ ์ค„์ด๊ณ  ๋” ๊ฐ•๋ ฅํ•˜๊ฒŒ ์บก์Šํ™”ํ•˜๋Š” ๊ฒƒ์ด ์Šน๋ฆฌ์ธ ์ด์œ :

๋‹จํŽธํ™”๋Š” ๋ณต์žกํ•œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ดํ•ดํ•˜๊ณ  ์œ ์ง€ ๊ด€๋ฆฌํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์˜ต์…˜์˜ ๋ถ„๋ฆฌ๋Š” ๊ทผ๋ณธ์ ์ธ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ๋ฅผ ํ๋ฆฌ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํ•˜๋‚˜์˜ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ž‘์—…ํ•  ๋•Œ ๊ด€๋ จ ์ฝ”๋“œ์— ๋Œ€ํ•œ ์˜ต์…˜ ๋ธ”๋ก ์ฃผ์œ„๋ฅผ ์ง€์†์ ์œผ๋กœ "์ ํ”„"ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ๋…ผ๋ฆฌ์  ๋ฌธ์ œ์™€ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋ฅผ ํ•จ๊ป˜ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ํ›จ์”ฌ ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ œ๊ฐ€ ์ œ์ถœํ•œ ๊ฒƒ ์™ธ์— ๊ฐœ์„ ํ•˜๋ ค๊ณ  ํ•˜๋Š” ํ‘œ์ค€ ์˜ˆ์ œ์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ์ œ์•ˆ์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.
์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์–ดํ•˜๋Š” ์ถœ๋ฐœ์ ์ด๋ผ๋ฉด ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ˜„์žฌ ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ๋Š” ์žฅํ™ฉํ•œ ํ‘œํ˜„์ด๋ผ๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ์žฌ์‚ฌ์šฉํ•  ์ฝ”๋“œ๊ฐ€ ๋งŽ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ OP์— ์„ค๋ช…๋œ ๋Œ€๋กœ ๋ฌธ์ œ๋ฅผ ์ž˜ ๋‚˜ํƒ€๋‚ด๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐœ์ธ์ ์œผ๋กœ ์†”๋ฃจ์…˜์—์„œ ์ฐพ๊ณ ์ž ํ•˜๋Š” ํŠน์„ฑ์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ข€ ๋” ์ƒ๊ฐํ•˜๊ณ  ์žˆ์—ˆ๊ณ , ํ˜„์žฌ Hooks ์ œ์•ˆ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋Š” ํฐ ๋ฌธ์ œ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊นจ๋‹ซ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Flutter ํ”„๋ ˆ์ž„์›Œํฌ์— ๋ณ‘ํ•ฉํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค: Locality and Encapsulation, ๋˜๋Š” ์˜คํžˆ๋ ค ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค. Hooks์˜ ๋””์ž์ธ์€ ์ „์—ญ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: ํ˜„์žฌ ๋นŒ๋“œ ์ค‘์ธ ์œ„์ ฏ์„ ์ถ”์ ํ•˜๋Š” ์ •์ ). IMHO ์ด๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ํ”ผํ•ด์•ผ ํ•˜๋Š” ๋””์ž์ธ ํŠน์„ฑ์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๋Š” API๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ๋งŒ๋“ค๋ ค๊ณ  ํ•˜๋ฏ€๋กœ ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ•ด๋‹น ๋งค๊ฐœ๋ณ€์ˆ˜ ์™ธ๋ถ€์˜ ๊ฐ’์œผ๋กœ ์•„๋ฌด ๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ํ™•์‹ ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ BuildContext๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. , useContext ํ•ด๋‹นํ•˜๋Š” ๋Œ€์‹ ). ์ด๊ฒƒ์ด ๋ชจ๋“  ์‚ฌ๋žŒ์ด ํ•„์—ฐ์ ์œผ๋กœ ์›ํ•˜๋Š” ํŠน์„ฑ์ด๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์‚ฌ๋žŒ๋“ค์€ Hooks๊ฐ€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด Hooks๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Flutter์—์„œ ๋” ๋งŽ์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์œผ๋ ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ „์—ญ ์ƒํƒœ(์˜ˆ: ๋ฐ”์ธ๋”ฉ์—์„œ)๋ฅผ ๊ฐ€์งˆ ๋•Œ๋งˆ๋‹ค ์šฐ๋ฆฌ๋Š” ๊ฒฐ๊ตญ ๊ทธ๊ฒƒ์„ ํ›„ํšŒํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Hooks๋Š” ์•„๋งˆ๋„ ์ปจํ…์ŠคํŠธ์— ๋Œ€ํ•œ ๋ฉ”์†Œ๋“œ์ผ ์ˆ˜ ์žˆ์ง€๋งŒ(๋‚˜๋Š” ๊ทธ๋“ค์ด ์ดˆ๊ธฐ ๋ฒ„์ „์— ์žˆ์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค), ์†”์งํžˆ, ์ €๋Š” ๊ทธ๊ฒƒ๋“ค์„ ํ˜„์žฌ์ฒ˜๋Ÿผ ๋ณ‘ํ•ฉํ•˜๋Š” ๋ฐ ๋งŽ์€ ๊ฐ€์น˜๋ฅผ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋ณ‘ํ•ฉ์€ ์„ฑ๋Šฅ ํ–ฅ์ƒ์ด๋‚˜ ํŠน์ • ๋””๋ฒ„๊น… ๋„๊ตฌ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ํŒจํ‚ค์ง€๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐ ์•ฝ๊ฐ„์˜ ์–ด๋“œ๋ฒค์ณ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ˜ผ๋ž€๋งŒ ๊ฐ€์ค‘์‹œํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฆฌ์Šค๋„ˆ๋ธ”์„ ์ˆ˜์‹ ํ•˜๋Š” ๊ณต์‹์ ์ธ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•(AnimatedBuilder, StatefulWidget ๋ฐ useListenable)์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋‚˜์—๊ฒŒ ๊ฐ€์•ผ ํ•  ๊ธธ์€ ์ฝ”๋“œ ์ƒ์„ฑ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ œ์•ˆํ–ˆ์Šต๋‹ˆ๋‹ค. https://github.com/flutter/flutter/issues/63323

์ด๋Ÿฌํ•œ ์ œ์•ˆ์ด ์‹ค์ œ๋กœ ๊ตฌํ˜„๋œ๋‹ค๋ฉด ์•ฑ์—์„œ ๋งˆ๋ฒ• ๊ฐ™์€ SwiftUI์™€ ๊ฐ™์€ ์†”๋ฃจ์…˜์„ ์›ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์„ ๊ท€์ฐฎ๊ฒŒ ํ•˜์ง€ ์•Š๊ณ  ํŒจํ‚ค์ง€๋งŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์•„๋Š” ํ•œ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ์•„์ง ๋™์˜ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ›„ํฌ์˜ ์œ ํšจ์„ฑ์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๋Š” ๊ฒƒ์€ ํ˜„ ๋‹จ๊ณ„์—์„œ ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์—์„œ ๋ช‡ ๋ฒˆ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋‹ค๋ฅธ ๋งŽ์€ ์†”๋ฃจ์…˜์ด ์žˆ์œผ๋ฉฐ ๊ทธ ์ค‘ ๋‹ค์ˆ˜๋Š” ์–ธ์–ด ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.
ํ›„ํฌ๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ์— ๋น„๊ต์  ์ €๋ ดํ•œ ๋‹ค๋ฅธ ๊ธฐ์ˆ ์˜ ๊ธฐ์กด ์†”๋ฃจ์…˜์˜ ํฌํŠธ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์€ SwiftUI ๋˜๋Š” Jetpack Compose๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ํ›„ํฌ์™€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋ฅผ ์ทจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. "named mixin" ์ œ์•ˆ ๋˜๋Š” Builders ์ œ์•ˆ์— ๋Œ€ํ•œ ๊ตฌ๋ฌธ ์„คํƒ•.

๋‚˜๋Š” ์ด ๋ฌธ์ œ์˜ ํ•ต์‹ฌ์ด StreamBuilder์™€ ๊ฐ™์€ ํŒจํ„ด์˜ ๋‹จ์ˆœํ™”๋ฅผ ์š”๊ตฌํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค.

  • StreamBuilder๋Š” ์ค‘์ฒฉ์œผ๋กœ ์ธํ•ด ๊ฐ€๋…์„ฑ/์“ฐ๊ธฐ์„ฑ์ด ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ฏน์Šค์ธ ๋ฐ ํ•จ์ˆ˜๋Š” StreamBuilder์— ๋Œ€ํ•œ ๊ฐ€๋Šฅํ•œ ๋Œ€์•ˆ์ด ์•„๋‹™๋‹ˆ๋‹ค.
  • ๋ชจ๋“  StatefulWidget์—์„œ StreamBuilder ๊ตฌํ˜„์„ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ๋Š” ๊ฒƒ์€ ํ•ฉ๋ฆฌ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€์˜ ๋ชจ๋“  ์ฃผ์„์€ ๋‹ค๋ฅธ ๋™์ž‘(์ผํšŒ์šฉ ๊ฐœ์ฒด ์ƒ์„ฑ, HTTP ์š”์ฒญ ๋งŒ๋“ค๊ธฐ ๋“ฑ) ๋˜๋Š” ๋‹ค๋ฅธ ๊ตฌ๋ฌธ ์ œ์•ˆ์— ๋Œ€ํ•œ StreamBuilder์˜ ๋Œ€์•ˆ์„ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋” ์ด์ƒ ๋ฌด์Šจ ๋ง์„ ํ•ด์•ผ ํ• ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์–ด์„œ ์–ด๋–ป๊ฒŒ ๋” ๋ฐœ์ „ํ•  ์ˆ˜ ์žˆ์„์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.
@Hixie ์ด ์ง„์ˆ ์—์„œ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ฑฐ๋‚˜ ๋™์˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@rrousselGit ์ด๊ฒƒ์„ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐ๋ชจ ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ๋‚ด๊ฐ€ ๋ฌธ์ œ๋ผ๊ณ  ์ดํ•ดํ•œ ๊ฒƒ์„ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐ๋ชจ ์•ฑ์„ ๋งŒ๋“ค๋ ค๊ณ  ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋ถ„๋ช…ํžˆ ๋‚˜๋Š” โ€‹โ€‹๊ทธ๊ฒƒ์„ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ("StreamBuilder์™€ ๊ฐ™์€ ํŒจํ„ด"๊ณผ ๋ฐ๋ชจ ์•ฑ์—์„œ ์ˆ˜ํ–‰ํ•œ ์ž‘์—…์˜ ์ฐจ์ด์ ์ด ๋ฌด์—‡์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.)

  • StreamBuilder๋Š” ์ค‘์ฒฉ์œผ๋กœ ์ธํ•ด ๊ฐ€๋…์„ฑ/์“ฐ๊ธฐ์„ฑ์ด ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹น์‹ ์€ ์ด๋ฏธ ์žฅํ™ฉํ•œ ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. ์ค‘์ฒฉ์€ ์žฅํ™ฉํ•จ์˜ ๋˜ ๋‹ค๋ฅธ ์ธก๋ฉด์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ค‘์ฒฉ์ด ์‹ค์ œ๋กœ ๋ฌธ์ œ๋ผ๋ฉด Padding, Expanded, Flexible, Center, SizedBox ๋ฐ ์‹ค์ œ ์ด์œ  ์—†์ด ์ค‘์ฒฉ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐํƒ€ ๋ชจ๋“  ์œ„์ ฏ์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ค‘์ฒฉ์€ ๋ชจ๋†€๋ฆฌ์‹ ์œ„์ ฏ์„ ๋ถ„ํ• ํ•˜์—ฌ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  StatefulWidget์—์„œ StreamBuilder ๊ตฌํ˜„์„ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ๋Š” ๊ฒƒ์€ ํ•ฉ๋ฆฌ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

StatefulWidget์ด ์ƒ์„ฑ ๋ฐ ํ๊ธฐํ•ด์•ผ ํ•˜๋Š” ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑ ๋ฐ ํ๊ธฐํ•˜๋Š” ์ฝ”๋“œ ํ–‰์„ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ๋Š”๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๊นŒ? ๋„ค, ์ •๋ง ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค.

์ž์ฒด ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑ/ํ๊ธฐํ•ด์•ผ ํ•˜๋Š” ์ˆ˜๋ฐฑ ๊ฐœ์˜ _different_ ์‚ฌ์šฉ์ž ์ •์˜ StatefulWidget์ด 10๊ฐœ ๋˜๋Š” ์‹ ์ด ๊ธˆ์ง€๋˜์–ด ์žˆ๋‹ค๋ฉด(ํ›„ํฌ ์šฉ์–ด์—์„œ "์‚ฌ์šฉ"), ""๋…ผ๋ฆฌ" ์žฌ์‚ฌ์šฉ ๋˜๋Š” ์ค‘์ฒฉ๋ณด๋‹ค ๊ฑฑ์ •ํ•ด์•ผ ํ•  ๋” ํฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฑฑ์ •ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด ์•ฑ์ด ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ทธ๋ ‡๊ฒŒ ๋งŽ์€ ๋‹ค๋ฅธ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ์ด์œ ์— ๋Œ€ํ•ด.

๊ณต์ •ํ•˜๊ฒŒ ๋งํ•˜์ž๋ฉด, ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ž์‹ ์˜ ์•ฑ์—์„œ ํŠน์ • ํŒจํ„ด์ด ํ•ฉ๋ฆฌ์ ์ด์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. (๊ทธ๋ ‡๋‹ค๊ณ  ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๋ฅผ ์ง€์›ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ๋Š” ์•„๋‹ˆ์ง€๋งŒ ์ตœ์†Œํ•œ ํŒจํ‚ค์ง€๊ฐ€ ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋„๋ก ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.) ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ stream.listen ๋˜๋Š” StreamBuilder(stream) ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€ ์•Š์€ ๊ฒฝ์šฐ

๊ณต์ •ํ•˜๊ฒŒ ๋งํ•˜์ž๋ฉด, ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ž์‹ ์˜ ์•ฑ์—์„œ ํŠน์ • ํŒจํ„ด์ด ํ•ฉ๋ฆฌ์ ์ด์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ๊ณผ ๊ฐ™์€ ํŽ˜์ด์ง€์— 100%์ž…๋‹ˆ๋‹ค.
๋ฌผ๋ก  ์‚ฌ๋žŒ๋“ค์€ ์•ฑ์—์„œ ์›ํ•˜๋Š” ๋Œ€๋กœ ๋ฌด์—‡์ด๋“  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์–ป์œผ๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์€ ์ด ์Šค๋ ˆ๋“œ์—์„œ ์„ค๋ช…ํ•˜๋Š” ๋ชจ๋“  ๋ฌธ์ œ์™€ ์–ด๋ ค์›€์ด ์ž˜๋ชป๋œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šต๊ด€์˜ ๊ฒฐ๊ณผ์ด๋ฉฐ ์‹ค์ œ๋กœ Dart ๋˜๋Š” Flutter์™€ ๊ฑฐ์˜ ๊ด€๋ จ์ด ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์ œ ์ƒ๊ฐ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๊ณณ๊ณณ์— ์ˆ˜์‹ญ ๊ฐœ์˜ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•˜๋Š” ์•ฑ์„ ์ž‘์„ฑํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ํ”„๋ ˆ์ž„์›Œํฌ์— "๊ฐœ์„ "์„ ์š”์ฒญํ•˜๊ธฐ ์ „์— ์•ฑ ๋””์ž์ธ์„ ๊ฒ€ํ† ํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์˜ˆ์ œ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ๋งŒ๋“  ํ›„ํฌ ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค.

  <strong i="10">@override</strong>
  Widget build(BuildContext context) {
    final value = useAnimation(animation);

    final screenHeight = MediaQuery.of(context).size.height;
    final textHeight =
        useMemoized(() => math.sqrt(screenHeight), [screenHeight]);

    return Text(
      'Change Duration',
      style: TextStyle(fontSize: 10.0 + value * textHeight),
    );
  }

๋‚˜๋Š” ์ด๊ฒƒ์— ๋Œ€ํ•ด ์ข‹์ง€ ์•Š์€ ๋Š๋‚Œ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚ด๋ถ€์˜ ์ผ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ณ  ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋””๋ฒ„๊ทธ ์ธ์‡„๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
์•„๋ž˜ ์ถœ๋ ฅ์—์„œ โ€‹โ€‹Listenable ํ›„ํฌ๊ฐ€ ๋ชจ๋“  ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ‹ฑ์—์„œ ์—…๋ฐ์ดํŠธ๋œ ๋‚ ์”จ๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฆฌ์Šค๋„ˆ๋ธ”์„ "์‚ฌ์šฉ"ํ•˜๋Š” ์œ„์ ฏ์ด ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๊นŒ? ๊ธฐ๊ฐ„์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋‚˜์š”? ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ต์ฒด๋˜์—ˆ์Šต๋‹ˆ๊นŒ?
๋ฉ”๋ชจ๋œ ํ›…, ๊ทธ๊ฒŒ ๋ญ”์ง€๋„ ๋ชจ๋ฅด๊ฒ ์–ด. ์•„๋งˆ๋„ ๊ฐ์ฒด๋ฅผ ์บ์‹œํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ชจ๋“  ๋‹จ์ผ ๋นŒ๋“œ์—์„œ ์œ„์ ฏ์€ ๊ฐ์ฒด๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๊นŒ? ๋ญ๋ผ๊ณ  ์š”? ์™œ์š”? ๋ฌผ๋ก  ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํŠธ๋ฆฌ ์œ„์˜ ๋‹ค๋ฅธ ์œ„์ ฏ์ด ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํด๋งํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ "๋ฐ˜์‘ํ˜•" ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ์ •๋ฐ˜๋Œ€์ธ ๋ฌธ์ž ๊ทธ๋Œ€๋กœ์˜ ํด๋ง ๋™์ž‘์ž…๋‹ˆ๋‹ค.

์„ค์ƒ๊ฐ€์ƒ์œผ๋กœ "new" ๋ฐ "old" ํ›„ํฌ๋Š” ๋ชจ๋‘ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค ์œ ํ˜•์„ ๊ฐ€์ง€๋ฉฐ ๋‘˜ ๋‹ค ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ–์ง€๋งŒ ํ•จ์ˆ˜๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ’์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค. _๋ชจ๋“  ๋‹จ์ผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ‹ฑ_์—.

์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ์–ป์€ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. ๋ฌดํ•œ๋Œ€์ž…๋‹ˆ๋‹ค.

/flutter (28121): Use hook:_ListenableHook
I/flutter (28121): Is this the current hook:false
I/flutter (28121): 1: --- inside shouldPreserveState ----
I/flutter (28121): Hook1:Instance of '_ListenableHook'
I/flutter (28121): Hook1 keys:null
I/flutter (28121): Hook2 :Instance of '_ListenableHook'
I/flutter (28121): Hook2 keys:null
I/flutter (28121): 2. Shoud we preserve the  state of _ListenableHook:true
I/flutter (28121): 3: --------------
I/flutter (28121): checking if the listenable did change
I/flutter (28121): Did the listenable change?false
I/flutter (28121): Use hook:_MemoizedHook<double>
I/flutter (28121): Is this the current hook:false
I/flutter (28121): 1: --- inside shouldPreserveState ----
I/flutter (28121): Hook1:Instance of '_MemoizedHook<double>'
I/flutter (28121): Hook1 keys:[1232.0]
I/flutter (28121): Hook2 :Instance of '_MemoizedHook<double>'
I/flutter (28121): Hook2 keys:[1232.0]
I/flutter (28121): iterating over the hooks keys
I/flutter (28121): 2. Shoud we preserve the  state of _MemoizedHook<double>:true
I/flutter (28121): Use hook:_ListenableHook
I/flutter (28121): Is this the current hook:false
I/flutter (28121): 1: --- inside shouldPreserveState ----
I/flutter (28121): Hook1:Instance of '_ListenableHook'
I/flutter (28121): Hook1 keys:null
I/flutter (28121): Hook2 :Instance of '_ListenableHook'
I/flutter (28121): Hook2 keys:null
I/flutter (28121): 2. Shoud we preserve the  state of _ListenableHook:true

์ด ๋ชจ๋“  ์ž‘์—…์€ ๋ชจ๋“  ๋‹จ์ผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ‹ฑ์—์„œ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. "final color = useAnimation"๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ํ›„ํฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด(animationColor);", ์ƒ‰์ƒ์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•ด ์ด์ œ ์œ„์ ฏ์ด ์—…๋ฐ์ดํŠธ๋˜์—ˆ๋Š”์ง€ _2_๋ฒˆ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์—ฌ๊ธฐ ์•‰์•„์„œ ์•ฑ ์ƒํƒœ๋‚˜ ์œ„์ ฏ ๋˜๋Š” ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์•ž๋’ค๋กœ ์›€์ง์ด๋Š” ํ…์ŠคํŠธ๋ฅผ ๋ณด๊ณ  ์žˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ํ›„ํฌ๋Š” ํŠธ๋ฆฌ/์œ„์ ฏ์ด ์—…๋ฐ์ดํŠธ๋˜์—ˆ๋Š”์ง€ ์ง€์†์ ์œผ๋กœ ํ™•์ธํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํŠน์ • ํ›„ํฌ๋ฅผ "์‚ฌ์šฉ"ํ•˜๋Š” ๋ชจ๋“  ์œ„์ ฏ์ด ์ด ํด๋ง ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋นŒ๋“œ ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ์ƒํƒœ ๊ฐœ์ฒด์˜ ์ดˆ๊ธฐํ™”/์—…๋ฐ์ดํŠธ/ํ๊ธฐ ๋…ผ๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์ž˜๋ชป๋œ ๋””์ž์ธ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์žฌ์‚ฌ์šฉ์„ฑ, ํ•ซ๋ฆฌ๋กœ๋“œ ๋˜๋Š” ์ธ์ง€ ๋ถ€ํ•˜์—์„œ ์–ป์€ ๊ฐœ์„  ์‚ฌํ•ญ์ด ์„ฑ๋Šฅ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์„ ์ •๋‹นํ™”ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.
๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ๋‚ด ์ƒ๊ฐ์—๋Š”. ํ›„ํฌ๋Š” ํŒจํ‚ค์ง€์ด๋ฏ€๋กœ ์ด๋“์ด ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ •๋‹นํ™”ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ๋‚ด๋ถ€์˜ ๋ชจ๋“  ๊ฒƒ์„ ์ถ”์ƒํ™”ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์–ธ์–ด ๊ธฐ๋Šฅ, ์ปดํŒŒ์ผ๋Ÿฌ ๋งˆ์ˆ  ๋˜๋Š” ์ถ”์ƒํ™”๊ฐ€ ๊ทธ๋Ÿฌํ•œ ๋ถˆํ•„์š”ํ•œ ๊ฒ€์‚ฌ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ StatefulWidget์„ ํ™•์žฅํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋Œ€์•ˆ์ด ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ, ์ˆ˜์—†์ด ํ•ด๊ณ ๋œ ์ผ.

@Hixie ๋‹น์‹ ์€ ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์œ„์— ๋‚˜์—ด๋œ ๊ธ€๋จธ๋ฆฌ ๊ธฐํ˜ธ ๋ชฉ๋ก์—์„œ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ฑฐ๋‚˜ ๋™์˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‚˜๋Š” ๋‹น์‹ ์ด ๋‚ด๊ฐ€ ๋ฌด์—‡์„ ๋ณด์—ฌ์ฃผ๊ธฐ๋ฅผ ์›ํ•˜๋Š”์ง€ ๋ชจ๋ฅธ ์ฑ„ ์˜ˆ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@Rudiksz ํ™•์‹คํžˆ ์šฐ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ๊ณ ๋ คํ•˜๋Š” ๋ชจ๋“  ์†”๋ฃจ์…˜์€ ์ƒํ™ฉ์„ ์•…ํ™”์‹œํ‚ค์ง€ ์•Š๋„๋ก ํ”„๋กœํŒŒ์ผ๋งํ•˜๊ณ  ๋ฒค์น˜๋งˆํ‚นํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. @TimWhiting์— ์ œ์ถœํ•œ ๋ฐ๋ชจ ์•ฑ์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ์ผ๋ถ€๋Š” ์—‰๋ง์ด ๋˜๊ธฐ ์‰ฌ์šด ์œ ํ˜•์˜ ํŒจํ„ด์„ ์ •ํ™•ํžˆ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. (๊ทธ๋ฆฌ๊ณ  ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๊ฐœ์„ ์˜ ์—ฌ์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์˜ TODO๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.)

@rrousselGit ๋„ˆ๋ฌด ์ฃผ๊ด€์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์— ๋Œ€ํ•ด ์žก์ดˆ์—

  • ์ฒซ์งธ, ๋‚˜๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ Streams๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ValueListenable์€ ๊ฑฐ์˜ ๋™์ผํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ํ›จ์”ฌ ๋” ๋‚˜์€ IMHO ํŒจํ„ด์ž…๋‹ˆ๋‹ค.
  • StreamBuilder๊ฐ€ ํŠนํžˆ ์ฝ๊ฑฐ๋‚˜ ์“ฐ๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ @satvikpendem์ด ์ด์ „ ์—
  • ๋ฏน์Šค์ธ๊ณผ ํ•จ์ˆ˜๊ฐ€ StreamBuilder์— ๋Œ€ํ•œ ๊ฐ€๋Šฅํ•œ ๋Œ€์•ˆ์ด ๋  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๊ด€ํ•ด์„œ๋Š” Hooks๊ฐ€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ŠคํŠธ๋ฆผ์„ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ฝค ์ž˜ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ•ด๊ฒฐ์ฑ…์ด ๋  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ณต์‚ฌ ๋ถ™์—ฌ๋„ฃ๊ธฐ ๊ตฌํ˜„๊ณผ ๊ด€๋ จํ•˜์—ฌ ์ฃผ๊ด€์ ์ธ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. initState/didUpdateWidget/dispose/build์— ๋กœ์ง์„ ๊ฐœ์ธ์ ์œผ๋กœ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์ง€ ์•Š๊ณ  ๋งค๋ฒˆ ์ƒˆ๋กœ ์ž‘์„ฑํ•˜๋Š”๋ฐ ๋Œ€๋ถ€๋ถ„ ๊ดœ์ฐฎ์•„ ๋ณด์ž…๋‹ˆ๋‹ค. "์ œ์–ด ๋ถˆ๋Šฅ" ์ƒํƒœ๊ฐ€ ๋˜๋ฉด StreamBuilder์™€ ๊ฐ™์€ ์œ„์ ฏ์— ํฌํ•จ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‹ค์‹œ ๋‚ด ์˜๊ฒฌ์€ ์•„๋งˆ๋„ ์—ฌ๊ธฐ์—์„œ ๊ด€๋ จ์ด ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ๊ท€ํ•˜๊ฐ€ ๋ณด๊ณ  ์žˆ๋Š” ๋ฌธ์ œ๋ฅผ ๋‚ด๊ฐ€ ๊ฒฝํ—˜ํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€๋Š” ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์˜ ๊ฒฝํ—˜์€ ๋‚ด ์˜๊ฒฌ๊ณผ ์ƒ๊ด€์—†์ด ์œ ํšจํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ๊ฒฝํ—˜ํ•˜๋Š” ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ๊ธฐ ์œ„ํ•ด ์ผํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๋น„๋ก ๋‚ด๊ฐ€ ๊ทธ ๋ฌธ์ œ๋ฅผ ๋Š๋ผ์ง€ ์•Š๋”๋ผ๋„ ๋ง์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ง์ ‘ ๋ฌธ์ œ๋ฅผ ๊ฒฝํ—˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์˜ ์œ ์ผํ•œ ํšจ๊ณผ๋Š” ์ด ํ† ๋ก ์—์„œ ๋ณด์•˜๋“ฏ์ด ๋‚ด๊ฐ€ ๋ฌธ์ œ๋ฅผ ์ž˜ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ๋” ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋‹น์‹ ์ด ์ฆ๋ช…ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์€ ๋‹น์‹ ์ด ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค ๋•Œ, ๋‹น์‹ ์ด ๋‹ค๋ฅธ ์ƒํ™ฉ์—์„œ ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ค์šด๋ฐ›์„ ์ˆ˜ ์žˆ์Œ์„ ๋งํ•˜์—ฌ ํ•ด๊ณ ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๋‹นํ•œ ์ •๋„๋กœ๋Š” ๊ทธ ๋ฐ๋ชจ์—, ๋ฐ›์•„ ๋“ค์ผ ์ƒ๊ฐํ•˜๋Š” ์ฝ”๋”ฉ ํŒจํ„ด (์ฆ‰, ๋ชจ๋“  ๊ด€๋ จ ์ƒํ™ฉ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด "์—…๋ฐ์ดํŠธ" ๋ถ€๋ถ„ ๋˜๋Š” ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋‹ค๋ฅธ ๋ถ€๋ถ„์„ ํฌํ•จํ•ด์•ผ ํ•จ) ๋˜๋Š” ์†”๋ฃจ์…˜์ด ํ•œ ๊ฐ€์ง€ ๊ฒฝ์šฐ์—๋Š” ์ž‘๋™ํ•˜์ง€๋งŒ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์—๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: ์ด์ „ ํ”ผ๋“œ๋ฐฑ์„ ํ†ตํ•ด ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—ฌ๋Ÿฌ ์œ„์น˜์—์„œ ์ œ๊ณต๋˜๊ณ  ์—ฌ๋Ÿฌ ์ƒํ™ฉ์—์„œ ์—…๋ฐ์ดํŠธ๋˜์–ด ์œ„์˜ ์†์„ฑ๊ณผ ๊ฐ™์€ ์†”๋ฃจ์…˜์ด ์ผ๋ฐ˜์ ์ธ ์ฝ”๋“œ๋ฅผ ์ œ์™ธํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ์ ์„ ๋ถ„๋ช…ํžˆ ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ๋‹น์‹ ์ด ๋‚˜์—๊ฒŒ "๋ช…๋ฐฑํ•œ" ์˜์—ญ์— ์žˆ๋Š” ๋ฌด์–ธ๊ฐ€์— ๋Œ€ํ•œ ์˜ˆ๋ฅผ ์š”๊ตฌํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์˜ˆ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์ง€๋งŒ, ๋‹น์‹ ์ด ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹น์‹ ์ด ๋ฌด์—‡์„ ๊ธฐ๋Œ€ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์ „ํ˜€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

ํ•  ๋ง์€ ์ด๋ฏธ ๋‹ค ํ–ˆ์Šต๋‹ˆ๋‹ค.
๋‹น์‹ ์ด ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€ ์•Š๊ณ  ๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๊ฒƒ์€ ๋‚˜ ์ž์‹ ์„ ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ์ผ๋ถ€ ์Šค๋‹ˆํŽซ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋Š” ๋‚˜ ์ž์‹ ์„ ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
์Šค ๋‹ˆํŽซ์ด ์œ ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•ด์„œ ์•„๋ฌด ๊ฒƒ๋„ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ฏน์Šค์ธ๊ณผ ํ•จ์ˆ˜๊ฐ€ StreamBuilder์— ๋Œ€ํ•œ ๊ฐ€๋Šฅํ•œ ๋Œ€์•ˆ์ด ๋  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๊ด€ํ•ด์„œ๋Š” Hooks๊ฐ€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ŠคํŠธ๋ฆผ์„ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ฝค ์ž˜ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ•ด๊ฒฐ์ฑ…์ด ๋  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ํ•จ์ˆ˜๋กœ ๊ฐ„์ฃผํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.
Iterable/Stream๊ณผ ์œ ์‚ฌํ•œ ์ƒˆ๋กœ์šด ์–ธ์–ด ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋Š” ํ›„ํฌ๊ฐ€ ํ•˜๋Š” ์ผ์„ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ƒํƒœ ๋˜๋Š” ์œ„์ ฏ์„ ๋‹ค์‹œ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ์—†์Šต๋‹ˆ๋‹ค.

mixins์˜ ๋ฌธ์ œ๋Š” OP์—์„œ ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค. TL;DR: ๋ณ€์ˆ˜์— ์ด๋ฆ„ ์ถฉ๋Œ์ด ์žˆ๊ณ  ๋™์ผํ•œ ๋ฏน์Šค์ธ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@rrousselGit ๊ธ€์Ž„์š”, ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋„ ์ƒ๊ด€์—†๊ณ  ์ œ๊ฐ€ ์š”๊ตฌํ•˜๋Š” ์˜ˆ์ œ๋Š” ๋ถ„๋ช…ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ช‡ ๊ฐ€์ง€ ๋ถ„๋ช…ํ•œ ์˜ˆ์ œ๋กœ ์‹œ์ž‘ํ•˜์—ฌ ๊ฑฐ๊ธฐ์—์„œ ๋ฐ˜๋ณตํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์˜ˆ๊ฐ€ ๋ช…๋ฐฑํ•˜๋‹ค๊ณ  ๋งํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ๋ฌธ์ œ๋Š”์ž…๋‹ˆ๋‹ค.
๋‚ด๊ฐ€ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋Š” ์ƒˆ๋กœ์šด ์˜ˆ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋งํ•ด์•ผ ํ•  ๋ชจ๋“  ๊ฒƒ์€ ์ด๋ฏธ ์ด ์Šค๋ ˆ๋“œ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์˜ˆ์— ์ถ”๊ฐ€ํ•  ๊ฒƒ์ด ์ƒ๊ฐ๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ FWIW ์ €๋Š” Riverpod๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜คํ”ˆ ์†Œ์Šค ๋‚ ์”จ ์•ฑ์„ ๋งŒ๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์™„๋ฃŒ๋˜๋ฉด ์—ฌ๊ธฐ์— ๋งํฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


์—ฌ๊ธฐ์—์„œ ๋…ผ์˜๋œ ๋ฌธ์ œ์™€ ๊ด€๋ จ๋œ ๋นŒ๋”์— ๋Œ€ํ•ด ๋ช‡ ๊ฐ€์ง€ ์งˆ๋ฌธ์„ ํ•˜๋Š” ํŠธ์œ„ํ„ฐ ์„ค๋ฌธ์กฐ์‚ฌ๋ฅผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

https://twitter.com/remi_rousselet/status/1295453683640078336

ํˆฌํ‘œ๋Š” ์•„์ง ๋ณด๋ฅ˜ ์ค‘์ด์ง€๋งŒ ํ˜„์žฌ ์ˆซ์ž๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Screenshot 2020-08-18 at 07 01 44

200๋ช…์˜ ์‚ฌ๋žŒ๋“ค ์ค‘ 86%๊ฐ€ ์ค‘์ฒฉ์„ ํฌํ•จํ•˜์ง€ ์•Š๋Š” ๋นŒ๋”๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์›ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค ์ž์ฒด๊ฐ€ ๋งํ•ด์ค๋‹ˆ๋‹ค.

๋ถ„๋ช…ํžˆ ๋ง์”€๋“œ๋ฆฌ์ž๋ฉด ์ €๋Š” ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ง๋ผ๊ณ  ์ œ์•ˆํ•œ ์ ์ด ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๊ฒƒ์„ ํ•ด๊ฒฐํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋ฉด, ๊ทธ ๋ฌธ์ œ๋Š” ์ข…๊ฒฐ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด ๋งํฌ ํ•œ ์Šค ๋‹ˆํŽซ์„ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋งํฌ๋œ ์Šค๋‹ˆํŽซ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์„ ๋“œ๋ฆด ์ˆ˜ ์žˆ์ง€๋งŒ ์ด ์Šค๋‹ˆํŽซ์ด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ์ด์œ ๋ฅผ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ์ด๋Ÿฌํ•œ ์Šค๋‹ˆํŽซ์„ ์ปดํŒŒ์ผํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์ด ๋‹น์‹ ์ด ์›ํ•˜๋Š” ๊ฒƒ์ธ์ง€ ์˜์‹ฌ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ์€ ์ˆ˜๋งŽ์€ ValueListenableBuilder+TweenAnimationBuilder https://gist.github.com/rrousselGit/a48f541ffaaafe257994c6f98992fa73์— ๋Œ€ํ•œ ์š”์ง€์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ์€ ์ˆ˜๋งŽ์€ ValueListenableBuilder+TweenAnimationBuilder https://gist.github.com/rrousselGit/a48f541ffaaafe257994c6f98992fa73์— ๋Œ€ํ•œ ์š”์ง€์ž…๋‹ˆ๋‹ค.

FWIW, ์ด ํŠน์ • ์˜ˆ๋Š” mobx์—์„œ ๋” ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์‹ค์ œ๋กœ ํ›„ํฌ ๊ตฌํ˜„๋ณด๋‹ค ์งง์Šต๋‹ˆ๋‹ค.

Mobx์˜ ์˜ต์ €๋ฒ„๋ธ”์€ ์Šคํ…Œ๋กœ์ด๋“œ์˜ ValueNotifier์ด๊ณ  Observer ์œ„์ ฏ์€ Flutter์˜ ValueListenableBuilder๊ฐ€ ์ง„ํ™”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ•˜๋‚˜ ์ด์ƒ์˜ ValueNotifier๋ฅผ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ValueNotifier/ValueListenableBuilder ์ฝค๋ณด์— ๋Œ€ํ•œ ๋“œ๋กญ์ธ ๋Œ€์ฒด๊ฐ€ ๋œ๋‹ค๋Š” ๊ฒƒ์€ ์‹ค์ œ๋กœ ์ค‘์š”ํ•œ ์š”์†Œ์ธ ๊ด€์šฉ์  Flutter ์ฝ”๋“œ๋ฅผ ๊ณ„์† ์ž‘์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์—ฌ์ „ํžˆ Flutter์— ๋‚ด์žฅ๋œ Tween ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์—์„œ ์ƒˆ๋กœ์šด ์œ„์ ฏ/ํ›„ํฌ๋ฅผ ํ•™์Šต/๊ตฌํ˜„ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ(์ฆ‰, ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค) ํ›„ํฌ์˜ ์„ฑ๋Šฅ ์ €ํ•˜๋„ ์—†์Šต๋‹ˆ๋‹ค.

import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'counters.dart';

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

class MyApp extends StatelessWidget {
  <strong i="13">@override</strong>
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home1(),
    );
  }
}

var counters = Counters();

class Home1 extends StatelessWidget {
  <strong i="14">@override</strong>
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Observer(
              builder: (context) => TweenAnimationBuilder<int>(
                duration: const Duration(seconds: 5),
                curve: Curves.easeOut,
                tween: IntTween(end: counters.firstCounter),
                builder: (context, value, child) {
                  return Text('$value');
                },
              ),
            ),
            RaisedButton(
              onPressed: () => counters.firstCounter += 100,
              child: Text('+'),
            ),
            // Both counters have voluntarily a different Curve and duration
            Observer(
              builder: (context) => TweenAnimationBuilder<int>(
                duration: const Duration(seconds: 2),
                curve: Curves.easeInOut,
                tween: IntTween(end: counters.secondCounter),
                builder: (context, value, child) {
                  return Text('$value');
                },
              ),
            ),
            RaisedButton(
              onPressed: () => counters.secondCounter += 100,
              child: Text('+'),
            ),
            const Text('total:'),
            // The total must take into account the animation of both counters
            Observer(
              builder: (context) => TweenAnimationBuilder<int>(
                duration: const Duration(seconds: 5),
                curve: Curves.easeOut,
                tween: IntTween(
                    end: counters.firstCounter + counters.secondCounter),
                builder: (context, value, child) {
                  return Text('$value');
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Counters.dart๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

part 'counters.g.dart';

class Counters = _Counters with _$Counters;
abstract class _Counters with Store {
  <strong i="18">@observable</strong>
  int firstCounter = 0;

  <strong i="19">@observable</strong>
  int secondCounter = 0;
}

์• ๋‹ˆ๋ฉ”์ด์…˜ ๋นŒ๋”๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๋˜ ๋‹ค๋ฅธ ๊ตฌํ˜„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์ ฏ์˜ ๋นŒ๋“œ ๋ฐฉ๋ฒ•์€ ํ…œํ”Œ๋ฆฟ๊ณผ ๊ฐ™์€ ์˜๋ฏธ๋ก ์  html ํŒŒ์ผ๊ณผ ๊ฐ™์ด ์ตœ๋Œ€ํ•œ ์ˆœ์ˆ˜ํ•ฉ๋‹ˆ๋‹ค.

https://gist.github.com/Rudiksz/cede1a5fe88e992b158ee3bf15858bd9

@Rudiksz "์ด๊ณ„" ํ•„๋“œ์˜ ๋™์ž‘์ด ์Šค๋‹ˆํŽซ์—์„œ ๊นจ์กŒ์Šต๋‹ˆ๋‹ค. ๋‘ ์นด์šดํ„ฐ๊ฐ€ ํ•จ๊ป˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ ์‹œ๊ฐ„๊ณผ ๋‹ค๋ฅธ ๊ณก์„ ์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์™„๋ฃŒํ•˜๋Š” ์˜ˆ์ œ์™€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ด ์˜ˆ์ œ๊ฐ€ ValueListenableBuilder ๋ณ€ํ˜•์— ๋ฌด์—‡์„ ์ถ”๊ฐ€ํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ์š”์ ์— ๊ด€ํ•ด์„œ๋Š” TickerMode ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ œ๊ฑฐ๋˜๊ฑฐ๋‚˜ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ํ๊ธฐ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ TickerProvider ๊ฐ€ ๊นจ์กŒ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Mobx๋Š” ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์•ฐ๋น„์–ธํŠธ ์ƒํƒœ/ValueListenable vs Stores vs Streams๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, Mobx๊ฐ€ ์–ด๋–ค ์‹์œผ๋กœ๋“  ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•˜๋Š” ๋กœ์ปฌ ์ƒํƒœ/์ค‘์ฒฉ ๋นŒ๋”๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

โ€“โ€“โ€“โ€“

๋˜ํ•œ ํ›„ํฌ ์˜ˆ์—์„œ useAnimatedInt ๋Š” ํŒจํ‚ค์ง€๋กœ ์ถ”์ถœ๋  ์ˆ˜/์žˆ์–ด์•ผ ํ•˜๋ฉฐ ๊ฐœ๋ณ„ ํ…์ŠคํŠธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ์ด๊ณ„ ์‚ฌ์ด์˜ ์ง€์† ์‹œ๊ฐ„/๊ณก์„ ์ด ์ค‘๋ณต๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์„ ๋ช…์‹ฌํ•˜์‹ญ์‹œ์˜ค.

๊ณต์—ฐ์˜ ๊ฒฝ์šฐ Hooks๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹จ์ผ ์š”์†Œ๋งŒ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๋Š” ๋ฐ˜๋ฉด Builders๋Š” 2-4๊ฐœ ๋นŒ๋”๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ Hooks๋Š” ํ›จ์”ฌ ๋” ๋น ๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์Šค๋‹ˆํŽซ์—์„œ "์ด๊ณ„" ํ•„๋“œ์˜ ๋™์ž‘์ด ๊นจ์กŒ์Šต๋‹ˆ๋‹ค. ๋‘ ์นด์šดํ„ฐ๊ฐ€ ํ•จ๊ป˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ ์‹œ๊ฐ„๊ณผ ๋‹ค๋ฅธ ๊ณก์„ ์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์™„๋ฃŒํ•˜๋Š” ์˜ˆ์ œ์™€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹น์‹ ์€ ๋ถ„๋ช…ํžˆ ์˜ˆ์ œ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•˜์ง€๋„ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‹น์‹ ์˜ ์ฝ”๋“œ์™€ ๋˜‘๊ฐ™์ด ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ์š”์ ์€ TickerMode๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— TickerProvider๊ฐ€ ๊นจ์กŒ์Šต๋‹ˆ๋‹ค.

์ด๊ฒŒ ๋ฌด์Šจ ๋ง์ธ์ง€ ๋ชจ๋ฅด๊ฒ ๋„ค์š”. TickerMode๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” _your_ ์˜ˆ์ œ๋ฅผ ๋ฆฌํŒฉํ† ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณต์—ฐ์˜ ๊ฒฝ์šฐ Hooks๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹จ์ผ ์š”์†Œ๋งŒ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๋Š” ๋ฐ˜๋ฉด Builders๋Š” 2-4๊ฐœ ๋นŒ๋”๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Hooks๋Š” ํ›จ์”ฌ ๋” ๋น ๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋‹ˆ ๊ทธ๋ƒฅ ์•„๋‹ˆ. ํ›„ํฌ ์œ„์ ฏ์€ ๋ชจ๋“  ๋‹จ์ผ ๋นŒ๋“œ์—์„œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ง€์†์ ์œผ๋กœ ํด๋งํ•ฉ๋‹ˆ๋‹ค. valuelistenables๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋นŒ๋”๋Š” "๋ฐ˜์‘ํ˜•"์ž…๋‹ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ด ์˜ˆ์ œ๊ฐ€ ValueListenableBuilder ๋ณ€ํ˜•์— ๋ฌด์—‡์„ ์ถ”๊ฐ€ํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค .

๊ทธ๋ฆฌ๊ณ  Mobx๋Š” ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์•ฐ๋น„์–ธํŠธ ์ƒํƒœ/ValueListenable vs Stores vs Streams๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋…ผ์˜ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, Mobx๊ฐ€ ์–ด๋–ค ์‹์œผ๋กœ๋“  ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•˜๋Š” ๋กœ์ปฌ ์ƒํƒœ/ ์ค‘์ฒฉ ๋นŒ๋” ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋†๋‹ด์ด์‹œ๊ตฐ์š”. ๋‚˜๋Š” ๋‹น์‹ ์˜ ์˜ˆ๋ฅผ ๋“ค์–ด ์ค‘์ฒฉ๋œ ValueListenableBuilders *์™€ ํŠธ์œˆ ๋นŒ๋”๋ฅผ "๋‹ค๋ค˜์Šต๋‹ˆ๋‹ค"?! ๊ตฌ์ฒด์ ์œผ๋กœ ๋ฌธ์ œ๋กœ ์ œ๊ธฐํ•œ ์ .
๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ ์ด ๋ฌธ์žฅ์€ ์ด ํ† ๋ก ์— ๋Œ€ํ•œ ๋‹น์‹ ์˜ ์ „์ฒด์ ์ธ ํƒœ๋„๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ํ›„ํฌ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ "์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚จ"์ด์ง€๋งŒ ์†”๋ฃจ์…˜์œผ๋กœ ์‚ฌ์šฉํ•  ํ›„ํฌ์ธ์ง€ ์—ฌ๋ถ€๋Š” ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋Š”๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค.
์‰ฌ๊ฒŒ ํ•ด์ค˜

๋‹น์‹ ์€ ๋ถ„๋ช…ํžˆ ์˜ˆ์ œ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•˜์ง€๋„ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์™€ ๋˜‘๊ฐ™์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์นด์šดํ„ฐ๋Š” 5์ดˆ ๋™์•ˆ, ๋‘ ๋ฒˆ์งธ ์นด์šดํ„ฐ๋Š” 2์ดˆ ๋™์•ˆ ์›€์ง์ด๋ฉฐ ๋‘˜ ๋‹ค ๋‹ค๋ฅธ ๊ณก์„ ๋„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ค€ ๋‘ ์Šค๋‹ˆํŽซ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ์นด์šดํ„ฐ๋ฅผ ๋™์‹œ์— ์ฆ๊ฐ€์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๋ชจ๋“  ๋‹จ์ผ ํ”„๋ ˆ์ž„ ๋™์•ˆ "์ด๊ณ„"๊ฐ€ ์ •ํ™•ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์นด์šดํ„ฐ๊ฐ€ ๊ณ„์† ์›€์ง์ด๋Š” ๋™์•ˆ ๋‘ ๋ฒˆ์งธ ์นด์šดํ„ฐ๊ฐ€ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ค‘์ง€ํ•˜๋”๋ผ๋„

๋ฐ˜๋ฉด์— ๊ตฌํ˜„์—์„œ๋Š” 2๊ฐœ์˜ TweenAnimationBuilder๋ฅผ ํ•˜๋‚˜๋กœ ๋ณ‘ํ•ฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Observer(
  builder: (context) {
    return TweenAnimationBuilder<int>(
      duration: const Duration(seconds: 5),
      curve: Curves.easeOut,
      tween: IntTween(end: counters.firstCounter),
      builder: (context) {
        return Observer(
          valueListenable: secondCounter,
          builder: (context, value2, child) {
            return TweenAnimationBuilder<int>(
              duration: const Duration(seconds: 2),
              curve: Curves.easeInOut,
              tween: IntTween(end: counters.secondCounter),
              builder: (context, value2, child) {
                return Text('${value + value2}');
              },
            );
          },
        );
      },
    );
  },
)

๋‘ ๊ฐœ์˜ TweenAnimationBuilders ๋Š” ๋‘ ์นด์šดํ„ฐ ๋ชจ๋‘ ๊ฐœ๋ณ„์ ์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์กด์ค‘ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ฒซ ๋ฒˆ์งธ Observer ๋Š” counters.secondCounter ๊ด€์ฐฐํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ๊ฐœ์˜ Observer ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


์•„๋‹ˆ ๊ทธ๋ƒฅ ์•„๋‹ˆ. ํ›„ํฌ ์œ„์ ฏ์€ ๋ชจ๋“  ๋‹จ์ผ ๋นŒ๋“œ์—์„œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ง€์†์ ์œผ๋กœ ํด๋งํ•ฉ๋‹ˆ๋‹ค. valuelistenables๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋นŒ๋”๋Š” "๋ฐ˜์‘ํ˜•"์ž…๋‹ˆ๋‹ค.

Element ๊ฐ€ ํ•˜๋Š” ์ผ์„ ๋ฌด์‹œํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ›„ํฌ๊ฐ€ ํ•˜๋Š” ์ผ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ runtimeType๊ณผ ํ‚ค๋ฅผ ๋น„๊ตํ•˜๊ณ  ์ƒˆ ์š”์†Œ๋ฅผ ๋งŒ๋“ค์ง€ ๊ธฐ์กด ์š”์†Œ๋ฅผ ์—…๋ฐ์ดํŠธํ• ์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์˜ ์˜ˆ๋ฅผ ์ทจํ•˜๊ณ  ์ค‘์ฒฉ๋œ ValueListenableBuilders * ๋ฐ ํŠธ์œˆ ๋นŒ๋”๋ฅผ "๋‹ค๋ฃจ์—ˆ์Šต๋‹ˆ๋‹ค"

์ด ๊ฐœ์ˆ˜ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ์–ด๋–ค ์ค‘์ฒฉ์ด ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๊นŒ?

Observer(
  builder: (context) => TweenAnimationBuilder<int>(
    duration: const Duration(seconds: 5),
    curve: Curves.easeOut,
    tween: IntTween(end: counters.firstCounter),
    builder: (context, value, child) {
      return Text('$value');
    },
  ),
),

๋‹ค์Œ๊ณผ ๋‹ค๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ValueListenableBuilder<int>(
  valueListenable: firstCounter,
  builder: (context, value, child) => TweenAnimationBuilder<int>(
    duration: const Duration(seconds: 5),
    curve: Curves.easeOut,
    tween: IntTween(end: value),
    builder: (context, value, child) {
      return Text('$value');
    },
  ),
),

์ค‘์ฒฉ ์ธก๋ฉด์—์„œ.

์š”์ ์„ ์–ธ๊ธ‰ํ•˜๋Š” ๊ฒฝ์šฐ ์ด์ „์— ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ TickerProvider / TickerMode ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค. vsync ๋Š” SingleTickerProviderClientStateMixin ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ป์–ด์•ผ ํ•˜๋ฉฐ ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š” ์Œ์†Œ๊ฑฐ ๋…ผ๋ฆฌ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋‚ด ๊ธฐ์‚ฌ์—์„œ ์ด๊ฒƒ์„ ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค. https://dash-overflow.net/articles/why_vsync/

๊ทธ๋ฆฌ๊ณ  ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์›๋ž˜ TweenAnimationBuilder๊ฐ€ ํ•„์š”ํ•œ ๋ชจ๋“  ์œ„์น˜์—์„œ Tween ๋…ผ๋ฆฌ๋ฅผ ๋‹ค์‹œ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋…ผ๋ฆฌ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ์‚ฌ์†Œํ•˜์ง€ ์•Š๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•˜๋ฉด ์ƒ๋‹นํ•œ ์ค‘๋ณต์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ค€ ๋‘ ์Šค๋‹ˆํŽซ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ์นด์šดํ„ฐ๋ฅผ ๋™์‹œ์— ์ฆ๊ฐ€์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๋ชจ๋“  ๋‹จ์ผ ํ”„๋ ˆ์ž„ ๋™์•ˆ "์ด๊ณ„"๊ฐ€ ์ •ํ™•ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์นด์šดํ„ฐ๊ฐ€ ๊ณ„์† ์›€์ง์ด๋Š” ๋™์•ˆ ๋‘ ๋ฒˆ์งธ ์นด์šดํ„ฐ๊ฐ€ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ค‘์ง€ํ•˜๋”๋ผ๋„

๋ฐ˜๋ฉด์— ๊ตฌํ˜„์—์„œ๋Š” 2๊ฐœ์˜ TweenAnimationBuilder๋ฅผ ํ•˜๋‚˜๋กœ ๋ณ‘ํ•ฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋„ค, ๊ทธ๊ฑด ์ œ๊ฐ€ ๊ธฐ๊บผ์ด ํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ์ ˆ์ถฉ์•ˆ์ž…๋‹ˆ๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ์‹œ๊ฐ์  ํ”ผ๋“œ๋ฐฑ์ผ ๋ฟ์ด๊ณ  ์ •ํ™•์„ฑ์ด ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๋ฅผ ์‰ฝ๊ฒŒ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋ชจ๋‘ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด ์ด์˜๋ฅผ ์ œ๊ธฐํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ์ •ํ™•ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋™์‹œ์— ์ฝ”๋“œ๋ฅผ ๋”์šฑ ๊น”๋”ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋‘ ๋ฒˆ์งธ ๋ฒ„์ „์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์š”์ ์„ ์–ธ๊ธ‰ํ•˜๋Š” ๊ฒฝ์šฐ ์ด์ „์— ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ TickerProvider/TickerMode๋ฅผ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค. vsync๋Š” SingleTickerProviderClientStateMixin์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€์ ธ์™€์•ผ ํ•˜๋ฉฐ ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š” ์Œ์†Œ๊ฑฐ ๋…ผ๋ฆฌ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์œ„์ ฏ์—์„œ tickerprovider๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ์นด์šดํ„ฐ์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋„ ํ๊ธฐํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์„ธ๋ถ€ ์‚ฌํ•ญ์€ ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ์‰ฌ์›Œ์„œ ์˜ˆ์ œ์— ์•„๋ฌด๊ฒƒ๋„ ์ถ”๊ฐ€ํ•  ๊ฒƒ ๊ฐ™์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์—์„œ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ๋“ค์„ ์—ฟ๋ณด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” Counter() ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๊ท€ํ•˜์˜ ์˜ˆ์ œ์™€ ๊ทธ ์ด์ƒ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์›๋ž˜ TweenAnimationBuilder๊ฐ€ ํ•„์š”ํ•œ ๋ชจ๋“  ์œ„์น˜์—์„œ Tween ๋…ผ๋ฆฌ๋ฅผ ๋‹ค์‹œ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋…ผ๋ฆฌ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ์‚ฌ์†Œํ•˜์ง€ ์•Š๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•˜๋ฉด ์ƒ๋‹นํ•œ ์ค‘๋ณต์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋ญ๋ผ๊ณ  ์š”? ์™œ์š”? ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”. Counter ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‘ ๊ฐœ ์ด์ƒ ๋งŒ๋“ค๊ณ  ๋‹ค์–‘ํ•œ ์œ„์ ฏ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@Rudiksz ๊ท€ํ•˜์˜ ์†”๋ฃจ์…˜์ด ์‹ค์ œ๋กœ ์ œ์‹œ๋œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๋งํ•œ๋‹ค

๋‚˜๋Š” Counter() ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๊ท€ํ•˜์˜ ์˜ˆ์ œ์™€ ๊ทธ ์ด์ƒ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์•„์ง

๋„ค, ๊ทธ๊ฑด ์ œ๊ฐ€ ๊ธฐ๊บผ์ด ํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ์ ˆ์ถฉ์•ˆ์ž…๋‹ˆ๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ์‹œ๊ฐ์  ํ”ผ๋“œ๋ฐฑ์ผ ๋ฟ์ด๊ณ  ์ •ํ™•์„ฑ์ด ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๋ฅผ ์‰ฝ๊ฒŒ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋ชจ๋‘ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์œ„์ ฏ์—์„œ tickerprovider๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ์นด์šดํ„ฐ์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋„ ํ๊ธฐํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์„ธ๋ถ€ ์‚ฌํ•ญ์€ ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ์‰ฌ์›Œ์„œ ์˜ˆ์ œ์— ์•„๋ฌด๊ฒƒ๋„ ์ถ”๊ฐ€ํ•  ๊ฒƒ ๊ฐ™์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์—์„œ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ๋“ค์„ ์—ฟ๋ณด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@rrousselGit ์˜ ํ›„ํฌ ๋ฒ„์ „๊ณผ ํ‘œ๋ฉด์ ์œผ๋กœ๋งŒ ๋™์ผํ•œ ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ–ˆ์ง€๋งŒ, ํ›„ํฌ ๋ฒ„์ „์— ํฌํ•จ๋œ ๋ถ€๋ถ„์„ ์ƒ๋žตํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ๋Š” ๋™์ผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ๋น„๊ต๊ฐ€ ๋˜์ง€ ์•Š์ฃ ? ์ œ์•ˆ๋œ ์†”๋ฃจ์…˜๊ณผ ์†”๋ฃจ์…˜์„ ๋น„๊ตํ•˜๋ ค๋ฉด ์†”๋ฃจ์…˜์„ ํฌํ•จํ•˜์ง€ ์•Š์€ ์ด์œ ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๋Š” ๋Œ€์‹  ์š”๊ตฌ ์‚ฌํ•ญ๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด @TimWhiting ์˜ ์ €์žฅ์†Œ๋ฅผ ๋งŒ๋“œ๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐ๋˜๋Š” ๊ฒฝ์šฐ ์†”๋ฃจ์…˜์„ ์ œ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹น์‹ ์€ ๋ถ„๋ช…ํžˆ ์˜ˆ์ œ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•˜์ง€๋„ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์™€ ๋˜‘๊ฐ™์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์•„๋‹ˆ ๊ทธ๋ƒฅ ์•„๋‹ˆ.

๋†๋‹ด์ด์‹œ๊ตฐ์š”. ๋‚˜๋Š” ๋‹น์‹ ์˜ ์˜ˆ๋ฅผ ์ทจํ•˜๊ณ  ์ค‘์ฒฉ๋œ ValueListenableBuilders * ๋ฐ ํŠธ์œˆ ๋นŒ๋”๋ฅผ "๋‹ค๋ฃจ์—ˆ์Šต๋‹ˆ๋‹ค"

์ด๋Ÿฌํ•œ ๋น„๋‚œ์€ ์‚ผ๊ฐ€ํ•ด ์ฃผ์‹ญ์‹œ์˜ค. ์ด๋Ÿฌํ•œ ๋น„๋‚œ์€ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ์•Š๊ณ  ์ด ์Šค๋ ˆ๋“œ๋ฅผ ์•…๋ž„ํ•˜๊ฒŒ ๋งŒ๋“ค ๋ฟ์ž…๋‹ˆ๋‹ค. ์ƒ๋Œ€๋ฐฉ์„ ๋น„๋ฐฉํ•˜๊ฑฐ๋‚˜ ๋น„๋ฐฉํ•˜๊ฑฐ๋‚˜ ํ™”๋‚ด์ง€ ์•Š๊ณ  ์š”์ ์„ ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ œ๊ฐ€ ์ด ์Šค๋ ˆ๋“œ์—์„œ ๋ณธ ๋Œ“๊ธ€์˜ ํšจ๊ณผ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์ž์‹ ์˜ ๊ฒŒ์‹œ๋ฌผ์— ์ด๋ชจํ‹ฐ์ฝ˜์œผ๋กœ ๋ฐ˜์‘ํ•˜๋Š” ํšจ๊ณผ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

@rrousselGit

๋งํฌ๋œ ์Šค๋‹ˆํŽซ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์„ ๋“œ๋ฆด ์ˆ˜ ์žˆ์ง€๋งŒ ์ด ์Šค๋‹ˆํŽซ์ด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ์ด์œ ๋ฅผ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ์ด๋Ÿฌํ•œ ์Šค๋‹ˆํŽซ์„ ์ปดํŒŒ์ผํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์ด ๋‹น์‹ ์ด ์›ํ•˜๋Š” ๊ฒƒ์ธ์ง€ ์˜์‹ฌ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋‹จ์ˆœํ•œ ์Šค๋‹ˆํŽซ๋ณด๋‹ค ๋” ์ •๊ตํ•œ ์•ฑ์„ ์š”์ฒญํ•˜๋Š” ์ด์œ ๋Š” ๋‚ด๊ฐ€ ๊ท€ํ•˜์˜ ์Šค๋‹ˆํŽซ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ฒ˜๋ฆฌํ•œ ์˜ˆ์ œ๋ฅผ ๊ฒŒ์‹œํ–ˆ์„ ๋•Œ, ๋‹น์‹ ์ด ๊ทธ๊ฒƒ์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๋‹ค๋ฅธ ๊ฒฝ์šฐ๋„ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‹ค๊ณ  ๋งํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. '(์˜ˆ: didUpdateWidget์„ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์ด๋Ÿฌํ•œ ์Šค๋‹ˆํŽซ ์ค‘ ๋‘ ๊ฐœ๋ฅผ ๋‚˜๋ž€ํžˆ ๋‘๋Š” ๊ฒƒ์„ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌํ•˜๊ณ ์ž ํ•˜๋Š” ๊ธฐํƒ€ ์™„๋ฒฝํ•˜๊ฒŒ ํ•ฉ๋ฆฌ์ ์ธ ๊ฒƒ). ์ข€ ๋” ์ •๊ตํ•œ ์•ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด ์†”๋ฃจ์…˜์ด ํ™•๋ณด๋˜๋ฉด ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ƒˆ๋กœ์šด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” "๊ณ ๋ฏผ" ์ˆœ๊ฐ„์ด ์—†๋„๋ก ์ถฉ๋ถ„ํžˆ ์ •๊ตํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๋ฌด์–ธ๊ฐ€๋ฅผ ๋†“์น  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์ง€๋งŒ ์•„์ด๋””์–ด๋Š” ๊ธฐํšŒ๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋‹ค์ง€ ํ™˜์˜๋ฐ›์ง€ ๋ชปํ•˜๋Š” ์ตœ๊ทผ ๊ฒŒ์‹œ๋ฌผ๊ณผ ๊ด€๋ จํ•˜์—ฌ ์—ฌ๋Ÿฌ๋ถ„, ์ž‘์€ ์˜ˆ์ œ๋กœ ์™”๋‹ค ๊ฐ”๋‹ค ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค @TimWhiting ์˜ repo์—์„œ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์ง‘์ค‘ํ•ฉ์‹œ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ด๋ฏธ ๋…ผ์˜ํ•œ ๋ฐ”์™€ ๊ฐ™์ด, ์ž‘์€ ์˜ˆ๋Š” ๋Œ€์•ˆ์ด ์‹ค์ œ๋กœ ์ž˜ ์ž‘๋™ํ•จ์„ ์ž…์ฆํ•˜๊ธฐ์— ์ถฉ๋ถ„ํžˆ ๋Œ€ํ‘œํ•  ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ •๊ตํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ชจ๋“  ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐ๋˜๋Š” ๊ฒฝ์šฐ ์†”๋ฃจ์…˜์„ ์ œ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค ์ดํ›„์— ์š”๊ตฌ ์‚ฌํ•ญ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‘ ๊ฐ€์ง€ ํ•ด๊ฒฐ์ฑ…์„ ์ œ์‹œํ–ˆ๋‹ค. ํƒ€ํ˜‘์„ ํ•˜๋Š” ๊ฒƒ(๋งค์šฐ ํ•ฉ๋ฆฌ์ ์ธ ๊ฒƒ)๊ณผ ์ œ๊ณต๋œ ์˜ˆ์ œ๋ฅผ ์ •ํ™•ํžˆ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ.

@rrousselGit ์˜ ํ›„ํฌ ๋ฒ„์ „๊ณผ ํ‘œ๋ฉด์ ์œผ๋กœ๋งŒ ๋™์ผํ•œ ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ๋™์ผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

"ํ›„ํฌ ์†”๋ฃจ์…˜"์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ValueListenableBuilder ์˜ˆ์ œ๋ฅผ ๊ตฌํ˜„ํ–ˆ์œผ๋ฉฐ ํŠนํžˆ "์ค‘์ฒฉ ๋ฌธ์ œ"์— ์ค‘์ ์„ ๋‘ก๋‹ˆ๋‹ค. ํ›„ํฌ๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ผ์„ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ €๋Š” ๋‹จ์ˆœํžˆ ๋ถˆ๋งŒ ๋ชฉ๋ก์˜ ํ•œ ํ•ญ๋ชฉ์„ ๋Œ€์ฒด ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ† ๋ก ์— ์™ธ๋ถ€ ํŒจํ‚ค์ง€๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ €๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

์žฌ์‚ฌ์šฉ์„ฑ: ์•„๋ž˜ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์˜ ์˜ˆ๋ฅผ ์‚ดํŽด๋ณด์„ธ์š”.
https://github.com/Rudiksz/cbl_example

๋ฉ”๋ชจ:

  • ์œ„์ ฏ ์™ธ๋ถ€์—์„œ "๋…ผ๋ฆฌ"๋ฅผ ์บก์Šํ™”ํ•˜๊ณ  ๊ฑฐ์˜ HTML์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๋ฆฐ(lean) ์œ„์ ฏ์„ ๊ฐ–๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ํ›„ํฌ๊ฐ€ ๋ฎ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ๋ฎ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์š”์ ์ด ์•„๋‹ˆ๋‹ค. ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ํ›„ํฌ ํŒจํ‚ค์ง€๊ฐ€ ์•„๋‹ˆ๋ผ ์Šคํ†ก Flutter ํ”„๋ ˆ์ž„์›Œํฌ์— ๋Œ€ํ•œ ๋Œ€์•ˆ์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ๋งˆ์ผ€ํŒ… ํŒ€์ด ์ œ์‹œํ•  ์ˆ˜ ์žˆ๋Š” _๋ชจ๋“ _ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋‹ค๋ฃจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ Counter ๊ฐœ์ฒด ์ž์ฒด๋Š” ๋งค์šฐ ์œ ์—ฐํ•˜๋ฉฐ ์„œ๋กœ ๋‹ค๋ฅธ ์นด์šดํ„ฐ์˜ ํ•ฉ๊ณ„๋ฅผ ๊ณ„์‚ฐํ•˜๊ฑฐ๋‚˜ ๋ฐ˜์‘ํ˜•์œผ๋กœ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ์‘๋‹ตํ•ด์•ผ ํ•˜๋Š” ๋ณต์žกํ•œ ์œ„์ ฏ์˜ ์ผ๋ถ€๋กœ ๋…๋ฆฝ ์‹คํ–‰ํ˜•์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(AppBar ์ œ๋ชฉ ์ฐธ์กฐ).
  • ์‚ฌ์šฉํ•˜๋ ค๋Š” ์นด์šดํ„ฐ์˜ ์–‘, ์ดˆ๊ธฐ ๊ฐ’, ์ง€์† ์‹œ๊ฐ„, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์œ ํ˜•์„ ์‚ฌ์šฉ์ž ์ง€์ •ํ•˜๋Š” ๊ฒƒ์€ ์†Œ๋น„ ์œ„์ ฏ์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์˜ ์„ธ๋ถ€ ์‚ฌํ•ญ์—๋Š” ๋‹จ์ ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Flutter ํŒ€์ด ์œ„์ ฏ ์™ธ๋ถ€์—์„œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ์™€ ํŠธ์œˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ด๋–ป๊ฒŒ๋“  ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๊นจ๋œจ๋ฆด ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋งํ•˜๋ฉด ์ €๋Š” ์žฌ๊ณ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐœ์„ ํ•  ์ ์€ ๋ถ„๋ช…ํžˆ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž ์ง€์ • tickerprovider๋ฅผ ์†Œ๋น„ ์œ„์ ฏ์˜ mixin์œผ๋กœ ๋งŒ๋“  ๊ฒƒ์œผ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ํ•˜์ง€ ์•Š์•˜๋‹ค.
  • ์ด๊ฒƒ์€ "Builder" ํŒจํ„ด์— ๋Œ€ํ•œ ๋˜ ํ•˜๋‚˜์˜ ๋Œ€์•ˆ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. Builders๊ฐ€ ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ๋งํ•˜๋ฉด ํ•ด๋‹น ์‚ฌํ•ญ์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ž˜๋„ ์‚ฌ์‹ค์€ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ์—†์ด ์ฝ”๋“œ๋ฅผ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งˆ์Œ์— ๋“ค์ง€ ์•Š์œผ๋ฉด ์‚ฌ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ๋‚˜๋Š” ์ด๊ฒƒ์„ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ด๊ฒƒ์„ ์˜นํ˜ธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.

ํŽธ์ง‘: ์ด ์˜ˆ์ œ์—๋Š” ๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์• ๋‹ˆ๋ฉ”์ด์…˜๋˜๋Š” ๋™์•ˆ "์ฆ๊ฐ€"๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด ์นด์šดํ„ฐ๊ฐ€ ์žฌ์„ค์ •๋˜๊ณ  ํ˜„์žฌ ๊ฐ’์—์„œ ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด "์นด์šดํ„ฐ"์— ๋Œ€ํ•œ ์ •ํ™•ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ถ€๋Ÿฌ ์ˆ˜์ •ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ฆ๊ฐ€/๊ฐ์†Œ ๋ฐฉ๋ฒ•์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒŒ ๋‹ค์•ผ.

@Hixie ๋‚ด ์˜ˆ(https://github.com/TimWhiting/local_widget_state_approaches/blob/master/lib/hooks/animated_counter.dart)๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‹ค๊ณ  ๋งํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ท€ํ•˜์˜ ์˜๊ฒฌ์„ ํ•ด์„ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

๋˜ํ•œ Zoom/Google ๋ชจ์ž„ ํ†ตํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋˜ํ•œ ์ž์‹ ์˜ ๊ฒŒ์‹œ๋ฌผ์— ์ด๋ชจํ‹ฐ์ฝ˜์œผ๋กœ ๋ฐ˜์‘ํ•˜๋Š” ํšจ๊ณผ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์•„๋ฌด๊ฒƒ๋„. ๊ทธ๊ฒƒ์€ ์ „ํ˜€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ์™œ ๊บผ๋ƒˆ์–ด?

@rrousselGit ์ถฉ๋ถ„ํžˆ ์ข‹์€์ง€ ๋ณธ์ธ ๋งŒ์ด ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์˜ˆ์ œ๋ฅผ ๋ฆฌํŒฉํ† ๋งํ•˜์—ฌ ๊น”๋”ํ•˜๊ณ  ์งง๊ณ  ์ค‘๋ณต ์ฝ”๋“œ๊ฐ€ ์—†๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์œผ๋ฉด ๋งŒ์กฑํ•˜์‹ค๊นŒ์š”? ์•„๋‹ˆ๋ฉด ์ด ๋ฒ„๊ทธ๋ฅผ ์ถฉ์กฑ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ํ•ด๋‹น ์˜ˆ์ œ์—์„œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š” ์ง€์›ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ํ•ญ๋ชฉ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์ถฉ๋ถ„ํžˆ ์ข‹์€์ง€ ๋‹น์‹ ๋งŒ์ด ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ํŒ๋‹จํ•  ์ˆ˜ ์—†๋‹ค. ์šฐ์„ , ์œ ํ•œํ•œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์ง‘ํ•ฉ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํฌ์ฐฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด ์›ํ•˜๋Š” ๋Œ€๋กœ ์ผํ•˜๋Š” ๊ฒƒ์— ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์ง€๋งŒ ๊ทธ๊ฒƒ์ด ์šฐ๋ฆฌ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฐœ์ „์‹œํ‚ฌ์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ง€๋„๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ ๊ด€์ ์—์„œ ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์ˆ˜๋งŽ์€ ์ฝ”๋“œ ์กฐ๊ฐ์„ ์ œ๊ณตํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ‘œ์‹œ๋œ ์˜ˆ์ œ๊ฐ€ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋” ๋งŽ์€ ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ๋” ๋ช…ํ™•ํ•ด์งˆ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ฝ๊ธฐ์— ๋”์ฐํ•œ ์—ฌ๋Ÿฌ ์ค‘์ฒฉ ๋นŒ๋”๋‚˜ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋งŽ์€ 50์ค„์˜ ์ˆœ์ˆ˜ ์ƒ์šฉ๊ตฌ๋ฅผ ๋ณด๊ณ ๋„ ๋ฌธ์ œ๋ฅผ ์ถฉ๋ถ„ํžˆ ๊ฐ•๋ ฅํ•˜๊ฒŒ ์ž…์ฆํ•˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด ๊ฐˆ ๊ณณ์ด ์—†์Šต๋‹ˆ๋‹ค.

์ „์ฒด ์š”์ฒญ์ด ์บก์Šํ™”๋œ ์ƒํƒœ ์ผ ๋•Œ ๋ฏน์Šค์ธ์„ ์ œ์•ˆํ•˜๊ณ  ํ•จ์ˆ˜๊ฐ€ ์†”๋ฃจ์…˜์ธ ๊ฒƒ์€ ๋งค์šฐ ์ด์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ฏน์Šค์ธ์€ ์บก์Šํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์ œ์•ˆ์€ ์ œ๊ณต๋œ ๋ชจ๋“  ์˜ˆ์™€ ๊ทผ๊ฑฐ์˜ ์š”์ ์„ ๋†“์น˜๊ณ  ์—ฌ์ „ํžˆ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๊นŠ์€ ์˜คํ•ด๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์ œ ์ƒ๊ฐ์—๋Š” ์šฐ๋ฆฌ๊ฐ€ 2์ ์„ ์ด๊ธฐ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์–ด๋Š ์ชฝ๋„ ์‹ฌ๊ฐํ•˜๊ฒŒ ๋…ผ์Ÿํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

  1. ์ค‘์ฒฉ ๋นŒ๋”๋Š” ๋ณธ์งˆ์ ์œผ๋กœ ์ฝ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
  2. ์ค‘์ฒฉ๋œ ๋นŒ๋” ์™ธ์— ์œ„์ ฏ ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ์ƒํƒœ๋ฅผ ์บก์Šํ™”ํ•˜๊ณ  ๊ณต์œ ํ•˜๋Š” _๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค_.

์—ฌ๋Ÿฌ ๋ฒˆ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด Remi์˜ ์„ค๋ฌธ์กฐ์‚ฌ์—์„œ๋„ ๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ: ์šฐ๋ฆฌ๋Š” builder์˜ ์žฅํ™ฉํ•จ๊ณผ ์ค‘์ฒฉ๋œ ํด๋กœ์ € ์—†์ด builder์˜ ๊ธฐ๋Šฅ์„ ์›ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์™„์ „ํžˆ ์š”์•ฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ์—ฌ๊ธฐ์„œ ๊ณ„์† ์ง„ํ–‰ํ•˜๋ ค๋ฉด ์ถ”๊ฐ€ ์ฝ”๋“œ ์˜ˆ์ œ๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๊ฐ€ ์™„์ „ํžˆ ํ˜ผ๋ž€์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

Remi์˜ ์„ค๋ฌธ์กฐ์‚ฌ์— ๋”ฐ๋ฅด๋ฉด Flutter ๊ฐœ๋ฐœ์ž์˜ 80%๋Š” ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ์ฝ”๋“œ์—์„œ ์ค‘์ฒฉ๋œ ๋นŒ๋”๋ฅผ ํ”ผํ•˜๋Š” ์ผ์ข…์˜ ๊ธฐ๋Šฅ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ •๋ง๋กœ ๊ทธ ์ž์ฒด๋กœ ๋งํ•ด์ค๋‹ˆ๋‹ค. ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฐ์ •์ด ๋งค์šฐ ๋ช…ํ™•ํ•  ๋•Œ ์ด ์Šค๋ ˆ๋“œ์—์„œ ์šฐ๋ฆฌ์—๊ฒŒ์„œ ๊ทธ๊ฒƒ์„ ๊ฐ€์ ธ๊ฐˆ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋‚ด ๊ด€์ ์—์„œ ๋ฌธ์ œ๋Š” ๋ช…ํ™•ํ•˜๋ฉฐ ์—ฌ๊ธฐ์—์„œ ๊ทผ๊ฑฐ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๋ฐ ๋‹จ๋ฝ์„ ์ง€์ •ํ•˜๋Š” ๊ฒฝ์Ÿ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋ณด๋ฉด ํ›จ์”ฌ ๋” ๋ช…ํ™•ํ•ด์ง‘๋‹ˆ๋‹ค. Vue, React, Flutter๋Š” ๋ชจ๋‘ ์‚ฌ์ดŒ์ด๋ฉฐ ๋ชจ๋‘ React์—์„œ ํŒŒ์ƒ๋˜์—ˆ์œผ๋ฉฐ ์œ„์ ฏ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์—ฐ๊ฒฐํ•ด์•ผ ํ•˜๋Š” ์žฌ์‚ฌ์šฉ ์ƒํƒœ์™€ ๊ด€๋ จ๋œ ์ด ๋ฌธ์ œ์— ๋ชจ๋‘ ์ง๋ฉดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ๋ชจ๋‘ ์™œ ์ด์™€ ๊ฐ™์€ ๊ฒƒ์„ ๊ตฌํ˜„ํ–ˆ๋Š”์ง€ ์ž์„ธํžˆ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ๋ชจ๋‘ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

@rrousselGit ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ์˜ˆ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด, ์ˆ˜์‹ญ ๊ฐœ์˜ AnimationController๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜ Flutter๋กœ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

List<AnimationController> controllers = [];
int numAnimationControllers = 50;

<strong i="7">@override</strong>
void initState() {
    for (int i = 0; i < numAnimationControllers; i++)
        controllers.add(AnimationController(...));
}

<strong i="8">@override</strong>
void dispose() {
    for (int i = 0; i < numAnimationControllers; i++)
        controllers[i].dispose();
}

๊ทธ๋Ÿฌ๋‚˜ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฃจํ”„์—์„œ useAnimationController ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ์‚ฌ์†Œํ•œ ์˜ˆ๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์„ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

@satvikpendem

ํ”„๋กœ๋•์…˜ ์ค‘์ธ ๋‚ด ์•ฑ์˜ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ(ํŽ˜์ด์ง€ ๋งค๊น€๊ณผ ํ•จ๊ป˜ ์š”์ฒญ ๋ณด๋‚ด๊ธฐ์™€ ๊ฐ™์€ ์ผ๋ถ€ ํ›„ํฌ๋Š” ๋‹จ์ผ ํ›„ํฌ๋กœ ๋ณ‘ํ•ฉ/๋ฆฌํŒฉํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ๊ด€๋ จ์ด ์—†์Œ):

ํŽ˜์ด์ง€ ๋งค๊น€์œผ๋กœ ๊ฐ„๋‹จํ•œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ:

    final selectedTab = useState(SelectedTab.Wallet);
    final isDrawerOpen = useValueNotifier(false);
    final pageNo = useValueNotifier(0);
    final generalData = useValueNotifier(initialData);
    final services = useXApi();
    final isLoading = useValueNotifier(false);
    final waybillData = useValueNotifier<List<WaybillResponseModel>>([]);
    final theme = useTheme();
    final router = useRouter();

    fetchNextPage() async {
      if (isLoading.value || selectedTab.value != SelectedTab.Wallet) return;
      isLoading.value = true;
      final request = WaybillRequestModel()..pageNo = pageNo.value;
      final result = await services.waybillGetList(model: request);
      if (result.isOk && result.data.length > 0) {
        pageNo.value += 1;
        waybillData.value = [...waybillData.value, ...result.data];
      }
      isLoading.value = false;
    }

    // first fetch
    useEffect(() {
      fetchNextPage();
      return () {};
    }, []);

์–‘์‹ ๋…ผ๋ฆฌ(์ „ํ™”๋ฒˆํ˜ธ ํ™•์ธ ๋ฐ ์žฌ์ „์†ก ํƒ€์ด๋จธ๊ฐ€ ์žˆ๋Š” ๋กœ๊ทธ์ธ ์–‘์‹):

    final theme = useTheme();
    final loginState = useValueNotifier(LoginState.EnteringNumber);
    final error = useValueNotifier<String>(null);
    final phoneNumberController = useTextEditingController(text: "");
    final phoneNumberFocusNode = useMemoized(() => FocusNode(), []);
    final otpFocusNode = useMemoized(() => FocusNode(), []);
    final otpController = useTextEditingController(text: "");
    final appState = Provider.of<AppStateController>(context);
    final services = useXApi();
    final router = useRouter();
    final resendTimerValue = useValueNotifier(0);
    useEffect(() {
      var timer = Timer.periodic(Duration(seconds: 1), (t) async {
        if (resendTimerValue.value > 0) resendTimerValue.value--;
      });
      return () => timer.cancel();
    }, []);

    final doLogin = () async {
      // login
      loginState.value = LoginState.LoggingIn;
      final loginResult = await services.authLoginOrRegister(
        mobileNumber: phoneNumberController.text,
      );
      if (loginResult.isOk) {
        loginState.value = LoginState.EnteringOtpCode;
        WidgetsBinding.instance.addPostFrameCallback((_) {
          FocusScope.of(context).requestFocus(otpFocusNode);
        });
        resendTimerValue.value = 30;
      } else {
        error.value = loginResult.errorMessage;
        loginState.value = LoginState.EnteringNumber;
        WidgetsBinding.instance.addPostFrameCallback((_) {
          FocusScope.of(context).requestFocus(phoneNumberFocusNode);
        });
      }
    };

์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๊ฒฝ์šฐ @rrousselGit์ด ์ด๋ฏธ ์ถฉ๋ถ„ํ•œ ์˜ˆ๋ฅผ ์ œ๊ณตํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ์˜ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ํŠน์„ฑ์œผ๋กœ ์ธํ•ด ์œ„ ์ฝ”๋“œ์˜ ๋ฆฌํŒฉํ† ๋ง์ด ํ›จ์”ฌ ๋” ์‰ฝ๊ณ , ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ , ๊น”๋”ํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์‹ถ์ง€๋Š” ์•Š์ง€๋งŒ, ์›ํ•˜์‹ ๋‹ค๋ฉด ๋ฆฌํŒฉํ† ๋ง๋œ ๋ฒ„์ „๋„ ๊ฒŒ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ๋ฒˆ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด Remi์˜ ์„ค๋ฌธ์กฐ์‚ฌ์—์„œ๋„ ๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ: ์šฐ๋ฆฌ๋Š” builder์˜ ์žฅํ™ฉํ•จ๊ณผ ์ค‘์ฒฉ๋œ ํด๋กœ์ € ์—†์ด builder์˜ ๊ธฐ๋Šฅ์„ ์›ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์™„์ „ํžˆ ์š”์•ฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ์—ฌ๊ธฐ์„œ ๊ณ„์† ์ง„ํ–‰ํ•˜๋ ค๋ฉด ์ถ”๊ฐ€ ์ฝ”๋“œ ์˜ˆ์ œ๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๊ฐ€ ์™„์ „ํžˆ ํ˜ผ๋ž€์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ง ๊ทธ๋Œ€๋กœ Remi๊ฐ€ ์ œ๊ณตํ•œ ์˜ˆ์ œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์žฅํ™ฉํ•จ์„ ์ค„์ด๊ณ  ๋นŒ๋”์˜ ์ค‘์ฒฉ์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์˜ˆ์ œ๋ฅผ ์ œ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.
๋‚˜๋Š” ๊ทธ์˜ ์ฝ”๋“œ๋ฅผ ๋‚ด ์•ฑ์— ์ง‘์–ด๋„ฃ๊ณ  ์‹คํ–‰ํ•˜๊ณ  ๋‹ค์‹œ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์— ๊ด€ํ•œ ํ•œ ์ตœ์ข… ๊ฒฐ๊ณผ๋Š” ๊ฑฐ์˜ ๋™์ผํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์— ์š”๊ตฌ ์‚ฌํ•ญ์ด ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์šฐ๋ฆฌ๋Š” ๊ทน๋‹จ์ ์ธ ๊ฒฝ์šฐ์™€ ์ž ์žฌ์ ์ธ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋…ผ์˜ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทธ ๋Œ€์‹  ์ฃผ์ œ๋ฅผ ๋ฒ—์–ด๋‚œ ๊ฒƒ์œผ๋กœ ๋ถˆ๋ ธ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์—๋Š” Builders๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋ณต์žกํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์—๋Š” Builders๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ฃผ์žฅ์€ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ฐ„๊ฒฐํ•˜๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์‰ฌ์šด ๋ฐฉ๋ฒ•์ด ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•”์‹œ์ ์œผ๋กœ ์ด๋Š” Builders๊ฐ€ ๋ฐ˜๋“œ์‹œ ์žˆ์–ด์•ผ ํ•˜๋ฉฐ Flutter ์•ฑ์„ ๊ฐœ๋ฐœํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด๋ผ๋Š” ์˜๋ฏธ์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋ช…๋ฐฑํžˆ ๊ฑฐ์ง“์ž…๋‹ˆ๋‹ค.

๋ฐฉ๊ธˆ ์ž‘๋™ํ•˜๋Š” ๊ฐœ๋… ์ฆ๋ช… ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ๋นŒ๋”๋‚˜ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์œผ๋ฉฐ ์ด ํŠน์ • github ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” "๋ฌดํ•œํ•œ ๋ฌธ์ œ ์„ธํŠธ"๋ฅผ 100% ๋‹ค๋ฃจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฃผ์ œ๋ฅผ ๋ฒ—์–ด๋‚œ ๊ฒƒ์ด๋ผ๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.
์ฐธ๊ณ ๋กœ, ๋ฒค์น˜๋งˆํฌ๊ฐ€ ์—†์–ด๋„ ๋นŒ๋” ์œ„์ ฏ์„ ๋Šฅ๊ฐ€ํ•  ์ •๋„๋กœ ๋งค์šฐ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ๊ฒƒ์œผ๋กœ ํŒ๋ช…๋˜๋ฉด ๋งˆ์Œ์„ ๋ฐ”๊พธ๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. Mobx๊ฐ€ ์„ฑ๋Šฅ ๋ณ‘๋ชฉ ํ˜„์ƒ์ด ๋˜๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ•˜๋ฉด ์ฆ‰์‹œ Mobx๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ๋ฐ”๋‹๋ผ ๋นŒ๋”๋กœ ์ „ํ™˜ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Hixie๋Š” Google์—์„œ ์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ธ๋‚ด์‹ฌ์„ ๊ฐ–๊ณ  ์˜ˆ์˜ ๋ฐ”๋ฅด๊ฒŒ ๋Œ€ํ•ด์•ผ ํ•˜๋ฉฐ ์ฐธ์—ฌ๊ฐ€ ๋ถ€์กฑํ•˜๋‹ค๊ณ  ๋ถ€๋ฅผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ์„ ์€ ๋” ๋งŽ์€ ์˜ˆ๋ฅผ ์ œ์‹œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ˆ„๊ตฌ์˜ ์ด๋ฆ„๋„ ๋ถ€๋ฅด์ง€ ์•Š์•˜๊ณ  ์ธ์‹ ๊ณต๊ฒฉ๋„ ํ•˜์ง€ ์•Š์•˜๋‹ค. ๋‚˜๋Š” ์—ฌ๊ธฐ์— ์ œ์‹œ๋œ ์ฃผ์žฅ์—๋งŒ ๋ฐ˜์‘ํ–ˆ์œผ๋ฉฐ ๋‚ด ์˜๊ฒฌ์„ ๊ณต์œ ํ–ˆ์Šต๋‹ˆ๋‹ค.
(๋‚ด๊ฐ€ ์•„๋Š” ๊ฒƒ์€ ์ธ๊ธฐ๊ฐ€ ์—†๊ณ  ์†Œ์ˆ˜์— ๋ถˆ๊ณผํ•จ) ์‹ฌ์ง€์–ด ์‹ค์ œ ์นด์šดํ„ฐ ์˜ˆ์ œ๋ฅผ ์ฝ”๋“œ๋กœ ์ œ์‹œํ•˜๋ ค๊ณ  ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ๊ฒƒ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ ์‚ฌ๋ก€๊ฐ€ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ณ  ์ด๋ฅผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ์ƒ‰ํ•˜๊ณ  ์‹ถ์ง€๋งŒ, ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚˜๋Š” ๊ฒƒ์€ ์ผ์ข…์˜ ๋ถˆ์พŒํ•œ ์ผ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ธˆ์ง€๋‹นํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ์žƒ์„ ๊ฒƒ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋‹น์‹ ์„ ๋ถˆ๋Ÿฌ๋„ ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค.
๋‹น์‹ ์ด ๊ฒฝํ—˜ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ด๋“  ๊ฐ„์— ํ›„ํฌ๊ฐ€ ์œ ์ผํ•œ ํ•ด๊ฒฐ์ฑ…("React๊ฐ€ ๊ทธ๊ฒƒ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์—")์ด๊ณ  ๋Œ€์•ˆ์ด ๋‹น์‹ ์ด ์ƒ์ƒํ•˜๋Š” "๋ฌดํ•œํ•œ ๋ฌธ์ œ ์„ธํŠธ"๋ฅผ 100% ์ฑ„์šฐ์ง€ ์•Š๋Š” ํ•œ, ๋‹น์‹  ๋‘˜์€ ์ฃฝ์€ ์„ธํŠธ๋ผ๋Š” ๊ฒƒ์ด ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ์ฐธ์—ฌ๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Š” ํ•ฉ๋ฆฌ์ ์ด์ง€ ์•Š์œผ๋ฉฐ ์ง„์ •์œผ๋กœ ์ฐธ์—ฌํ•˜๋ ค๋Š” ์š•๊ตฌ๊ฐ€ ๋ถ€์กฑํ•จ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.


๋ฌผ๋ก  ์œ„์˜ ๋‚ด์šฉ์€ ๋ชจ๋‘ "๋‚ด ์ƒ๊ฐ์ผ ๋ฟ"์ž…๋‹ˆ๋‹ค.

๊ทธ ์˜ˆ์—์„œ ํ›„ํฌ์˜ ์œ ์šฉ์„ฑ์„ ๋ณด์•˜์ง€๋งŒ ๋‚ด ๊ฒฝ์šฐ์—๋Š” ๋งŽ์€ ๊ฐœ์ฒด๋ฅผ ํ•œ ๋ฒˆ์— ์ดˆ๊ธฐํ™”ํ•˜๋ ค๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๊ฒฝ์šฐ(์ด ๊ฒฝ์šฐ AnimationController s) ์ž‘๋™ ๋ฐฉ์‹์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋Š” ๋ฌด์—‡์ด๋“  ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๋Š” ์ด ๊ฒฝ์šฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๊นŒ?

๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๊ฒƒ์„ ๋Œ๋ฆฌ๋Š” ํ›„ํฌ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค

var x1 = useState(1);
var x2 = useState(2);
var x3 = useState(3);

์•ˆ์œผ๋กœ

var xs = []
for (int i = 0; i < 3; i++)
     xs[i] = useState(i);

ํ›„ํฌ ๊ทœ์น™์„ ์œ„๋ฐ˜ํ•˜์ง€ ์•Š๊ณ ? ์ผ๋ฐ˜ Flutter์— ๋™๋“ฑํ•œ ํ•ญ๋ชฉ์„ ๋‚˜์—ดํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ €๋Š” Flutter์˜ ํ›„ํฌ์— ๋Œ€ํ•ด ๊ฒฝํ—˜์ด ๋งŽ์ง€ ์•Š์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๋ชจ๋“  initState๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ ์‹œ ํ›„ํฌ ๊ฐœ์ฒด(์˜ˆ: AnimationController)์˜ ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ณ  ์ด๋ฏธ ์ธ์Šคํ„ด์Šคํ™”๋œ ํ๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ํ›„ํฌ์—์„œ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

@satvikpendem ์€ ํด๋ž˜์Šค์˜ ์†์„ฑ๊ณผ ๊ฐ™์€ ํ›„ํฌ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋ฃจํ”„์—์„œ ์ •์˜ํ•˜๊ฑฐ๋‚˜ ์ˆ˜๋™์œผ๋กœ ํ•˜๋‚˜์”ฉ ์ด๋ฆ„์„ ์ง€์ •ํ•ฉ๋‹ˆ๊นŒ?

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ•˜๋Š” ๊ท€ํ•˜์˜ ์˜ˆ์—์„œ

var x1 = useState(1);
var x2 = useState(2);
var x3 = useState(3);

์ด ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

var isLoading = useState(1);
var selectedTab = useState(2);
var username = useState(3); // text field

๊ฐ useState ๊ฐ€ ์ƒํƒœ ๋…ผ๋ฆฌ์˜ ๋ช…๋ช…๋œ ๋ถ€๋ถ„๊ณผ ์–ด๋–ป๊ฒŒ ๊ด€๋ จ๋˜์–ด ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? (์˜ˆ: isLoading์˜ useState๋Š” ์•ฑ์ด ๋กœ๋“œ ์ƒํƒœ์ผ ๋•Œ ์—ฐ๊ฒฐ๋จ)

๋‘ ๋ฒˆ์งธ ์Šค๋‹ˆํŽซ์—์„œ๋Š” ๋ฃจํ”„์—์„œ useState ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. useState ๋ฅผ ์ƒํƒœ ๋…ผ๋ฆฌ์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹Œ ๊ฐ€์น˜ ๋ณด์œ ์ž๋กœ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ชฉ๋ก์€ ListView ์— ํ•ญ๋ชฉ์˜ ๋ฌด๋ฆฌ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๋ฐ ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋ ‡๋‹ค๋ฉด ๋ชฉ๋ก์˜ ๋ชจ๋“  ํ•ญ๋ชฉ์„ ๊ฐœ๋ณ„์ ์œผ๋กœ๊ฐ€ ์•„๋‹Œ ์ƒํƒœ๋กœ ์ƒ๊ฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

final listData = useState([]);

์ด๊ฒƒ์€ useState ์— ๋Œ€ํ•œ ๊ฒƒ์ด๋ฉฐ ์กฐ๊ฑด์ด๋‚˜ ๋ฃจํ”„์—์„œ ์ผ๋ถ€ ํ›„ํฌ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์‚ฌ์šฉ ์‚ฌ๋ก€(๋งค์šฐ ๋“œ๋ฌผ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค)๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ํ›„ํฌ์—๋Š” ๋ฐ์ดํ„ฐ ๋ชฉ๋ก์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํ›„ํฌ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

var single = useTest("data");
var list = useTests(["data1", "data2"]);
// which is equivalent to
var single1 = useTest("data1");
var single2 = useTest("data2");

์—ฌ๋Ÿฌ AnimationController์™€ ๊ฐ™์€ ํ•ญ๋ชฉ ๋ฐฐ์—ด์ด ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ„๋„์˜ ํ›„ํฌ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ์ฒ˜์Œ์— ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  final animationControllers = useState<List<AnimationController>>([]);

  animationControllers.value = List<AnimationController>.generate(
    50,
    (_) => useAnimationController(),
  );

ํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ ํ•ญ๋ชฉ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด ์ž์‹ ์˜ ํ›„ํฌ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์ด๊ฒƒ์ด ์ž‘๋™ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

class _MultipleAnimationControllerHook extends Hook<MultipleAnimationController> {
  const _MultipleAnimationControllerHook({
    this.numControllers,
    this.duration,
    this.debugLabel,
    this.initialValue,
    this.lowerBound,
    this.upperBound,
    this.vsync,
    this.animationBehavior,
    List<Object> keys,
  }) : super(keys: keys);

  /// Take in number of controllers wanted
  /// This hook assumes all `AnimationController`s will have the same parameters
  final int numControllers; 

  final Duration duration;
  final String debugLabel;
  final double initialValue;
  final double lowerBound;
  final double upperBound;
  final TickerProvider vsync;
  final AnimationBehavior animationBehavior;

  <strong i="10">@override</strong>
  _AnimationControllerHookState createState() =>
      _AnimationControllerHookState();
}

class _AnimationControllerHookState
    extends HookState<AnimationController, _AnimationControllerHook> {
  List<AnimationController> _multipleAnimationController; // return a list instead of a singular item

  <strong i="11">@override</strong>
  void initHook() {
    super.initHook();
    for (int i = 0; i < hook.numControllers) // just added loops 
        _multipleAnimationController[i] = AnimationController(
          vsync: hook.vsync,
          duration: hook.duration,
          debugLabel: hook.debugLabel,
          lowerBound: hook.lowerBound,
          upperBound: hook.upperBound,
          animationBehavior: hook.animationBehavior,
          value: hook.initialValue,
        );
  }

  <strong i="12">@override</strong>
  void didUpdateHook(_AnimationControllerHook oldHook) {
      for (int i = 0; i < numControllers; i++) {
        if (hook.vsync != oldHook[i].vsync) {
           _multipleAnimationController[i].resync(hook.vsync);
        }

        if (hook.duration != oldHook[i].duration) {
          _multipleAnimationController[i].duration = hook.duration;
        }
      }
  }

  <strong i="13">@override</strong>
  MultipleAnimationController build(BuildContext context) {
    return _multipleAnimationController;
  }

  <strong i="14">@override</strong>
  void dispose() {
    _multipleAnimationController.map((e) => e.dispose());
  }
}

์ด๊ฒƒ์€ ๋‹จ์ผ ๋ฒ„์ „์˜ ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋‹จ์ˆœํžˆ ์—ฌ๋Ÿฌ ํ•ญ๋ชฉ์ด ์žˆ๋Š” ๋ฒ„์ „์— ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ณ  ๋Œ€์‹  ๋…ผ๋ฆฌ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•ด์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ non-hooks ์˜ˆ์ œ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์‹ถ์–ด๋„ ์ €๋„ ์•Œ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ์„ฑ ํผ์ฆ์˜ ์ด ๋ถ€๋ถ„์— ๋Œ€ํ•ด ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๊ณ ์œ ํ•œ AnimationController ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค์— ์ด ๋™์ž‘์„ ์บก์Šํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฃจํ”„ ๋‚ด๋ถ€์—์„œ ์ƒ์„ฑ๋œ ๊ฒฝ์šฐ ํ›„ํฌ๋„ ๊ทœ์น™์„ ์œ„๋ฐ˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์•„๋งˆ๋„ Vue๊ฐ€ ํ›„ํฌ ๊ตฌํ˜„์„ ์œ„ํ•œ ์กฐ๊ฑด๊ณผ ๋ฃจํ”„์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š” ๋ฐฉ์‹์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@satvikpendem

๋‚ด ์ง„์ˆ ์ด AnimationController ๋˜๋Š” useAnimationController ์œ ํšจํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ•˜๋‚˜ ์ด์ƒ์˜ AnimationController ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ˜๋“œ์‹œ ๋ฐฐ์—ด์— ์ €์žฅํ•  ํ•„์š”๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

useSingleTickProvider();
final animation1 = useAnimationController();
final animation2 = useAnimationController();
final animation3 = useAnimationController();
// ...
useEffect(() async {
  await animation1.forward();
  await Future.sleep(100);
  await animation1.reverse();
  await animation2.forward();
  await animation3.forward();
}, []);

(๋ชฉ๋ก์„ ๋งŒ๋“ค๊ณ  animation[0] ์™€ ๊ฐ™์ด ์ฐธ์กฐํ•˜์ง€ ์•Š์Œ)

์†”์งํžˆ ํ›„ํฌ์— ๋ฐ˜์‘ํ•˜๊ณ  ํ”Œ๋Ÿฌํ„ฐ์— ๋Œ€ํ•œ ๋‚ด ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด ๋ฃจํ”„์—์„œ ์ผ์ข…์˜ ํ›„ํฌ๋ฅผ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋•Œ๋„ ์†”๋ฃจ์…˜์€ ๊ฐ„๋‹จํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๊ธฐ ์‰ฌ์› ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. IMO๊ฐ€ "๋” ๊นจ๋—ํ•œ"์†”๋ฃจ์…˜์ธ ๊ฐ ๊ตฌ์„ฑ ์š”์†Œ(์œ„์ ฏ)๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์œผ๋กœ ํ™•์‹คํžˆ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ AnimationController ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋” ์‰ฌ์šด ๋ฐฉ๋ฒ•์ด ์žˆ์œผ๋ฉด ๊ท€ํ•˜์˜ ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

final ticker = useTickerProvider();
final controllers = useMemo(() => [AnimationController(ticker), AnimationController(ticker)], []);

useEffect(() {
  controllers.forEach(x => x.resync(ticker));
  return () => controllers.forEach(x => x.dispose());
}, [ticker, controllers]);

  • AnimationController ๊ฐ€ ๋™์ ์ด๋ฉด useState ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

(ํ‹ฐ์ปค๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋‹ค์‹œ ๋™๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค)

@rrousselGit ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ์˜ˆ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด, ์ˆ˜์‹ญ ๊ฐœ์˜ AnimationController๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜ Flutter๋กœ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

List<AnimationController> controllers = [];
int numAnimationControllers = 50;

<strong i="8">@override</strong>
void initState() {
    for (int i = 0; i < numAnimationControllers; i++)
        controllers.add(AnimationController(...));
}

<strong i="9">@override</strong>
void dispose() {
    for (int i = 0; i < numAnimationControllers; i++)
        controllers[i].dispose();
}

๊ทธ๋Ÿฌ๋‚˜ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฃจํ”„์—์„œ useAnimationController ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ์‚ฌ์†Œํ•œ ์˜ˆ๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์„ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ๋Š” ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋” ์ด์ƒ ์ปจํŠธ๋กค๋Ÿฌ ๋ชฉ๋ก์„ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ์ปจํŠธ๋กค๋Ÿฌ ๋กœ์ง์„ ํ•ญ๋ชฉ์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

Widget build(context) {
  return ListView(
    children: [
      for (var i = 0; i < 50; i++)
        HookBuilder(
          builder: (context) {
            final controller = useAnimationController();
          },
        ),
    ],
  );
}

์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ 50๊ฐœ์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ค์—ˆ์ง€๋งŒ ๋‹ค๋ฅธ ์œ„์ ฏ์ด ์†Œ์œ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์™œ ๊ทธ๊ฒƒ์ด ํ•„์š”ํ•œ์ง€์— ๋Œ€ํ•œ ์˜ˆ๋ฅผ ๊ณต์œ ํ•˜๊ณ  ํ›„ํฌ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ Tim์˜ ์ €์žฅ์†Œ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

Hixie๋Š” Google์—์„œ ์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ธ๋‚ด์‹ฌ์„ ๊ฐ–๊ณ  ์˜ˆ์˜ ๋ฐ”๋ฅด๊ฒŒ ๋Œ€ํ•ด์•ผ ํ•˜๋ฉฐ ์ฐธ์—ฌ๊ฐ€ ๋ถ€์กฑํ•˜๋‹ค๊ณ  ๋ถ€๋ฅผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ์„ ์€ ๋” ๋งŽ์€ ์˜ˆ๋ฅผ ์ œ์‹œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@Hixie , ๊ทธ๋ ‡๊ฒŒ ๋Š๋ผ์‹œ๋ฉด ๊ทธ๋ ‡๊ฒŒ ๋ง์”€ํ•ด ์ฃผ์„ธ์š”(์—ฌ๊ธฐ์—์„œ ๋˜๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์ €์—๊ฒŒ ์—ฐ๋ฝํ•˜์‹ญ์‹œ์˜ค).

๋‚˜๋Š” ๋ง ๊ทธ๋Œ€๋กœ Remi๊ฐ€ ์ œ๊ณตํ•œ ์˜ˆ์ œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์žฅํ™ฉํ•จ์„ ์ค„์ด๊ณ  ๋นŒ๋”์˜ ์ค‘์ฒฉ์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์˜ˆ์ œ๋ฅผ ์ œ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋…ผ๋ฆฌ๋ฅผ ๋‹ค๋ฅธ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ ์šฉํ•  ๋•Œ ์ด ์ฝ”๋“œ์—์„œ ๊ณตํ†ต ํŒจํ„ด์„ ์ถ”์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

OP์—์„œ ๋‚˜๋Š” ํ˜„์žฌ 3๊ฐ€์ง€ ์„ ํƒ์ด ์žˆ๋‹ค๊ณ  ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ค‘์ฒฉ ์ฝ”๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋” ๋ณต์žกํ•œ ์ƒํƒœ ๋…ผ๋ฆฌ๋กœ ํ™•์žฅ๋˜์ง€ ์•Š๋Š” ์ฝ”๋“œ๋ฅผ ์ธ์ˆ˜๋ถ„ํ•ดํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค( StreamBuilder ๋ฐ AsyncSnapshot ๋Š” ๋ณต์žกํ•œ ์ƒํƒœ ๋…ผ๋ฆฌ๋ผ๊ณ  ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค).
  • mixins/oop/...๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ผ๋ถ€ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ตฌ์„ฑํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜์ง€๋งŒ _์ž‘์€_ ๋น„ํŠธ๊ฐ€ ๋‹ค๋ฅธ ๋ชจ๋“  ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ๋‹ค์‹œ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ์— ๋„ˆ๋ฌด ํŠน์ •ํ•œ ์†”๋ฃจ์…˜์œผ๋กœ ๋๋‚ฉ๋‹ˆ๋‹ค.

์„ธ ๋ฒˆ์งธ ์„ ํƒ( Property ๋˜๋Š” addDispose ์ œ์•ˆ์˜ ์ดˆ๊ธฐ ๋ฐ˜๋ณต๊ณผ ๋™์ผํ•œ ๋ฒ”์ฃผ์— ์žˆ์Œ)์„ ์‚ฌ์šฉํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด์ „์— ํŒจํ„ด์„ ํŒ๋‹จํ•˜๊ธฐ ์œ„ํ•ด ํ‰๊ฐ€ ๊ทธ๋ฆฌ๋“œ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์— ๋Œ€ํ•œ ๋ณ€ํ˜•์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ํŠนํžˆ StreamBuilder ์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ฝ”๋“œ ์ค‘๋ณต ์—†์ด ๊ตฌํ˜„

์ด ๋ฒ„๊ทธ์— ๋Œ€ํ•œ ํ˜„์žฌ ๊ณ„ํš์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. https://github.com/flutter/flutter/issues/51752#issuecomment -675285066์—์„œ ์˜ˆ์ œ๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ˆœ์ˆ˜ Flutter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ํ•จ๊ป˜ ๋ณด์—ฌ์ฃผ๋Š” ์•ฑ์„ ๋งŒ๋“œ์„ธ์š”.
  2. ์—ฌ๊ธฐ์—์„œ ๋…ผ์˜๋œ ๋‹ค์–‘ํ•œ ํ•ต์‹ฌ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๊ณ  ์šฐ๋ฆฌ์˜ ์„ค๊ณ„ ์›์น™์— ๋งž๋Š” ์˜ˆ์ œ์— ๋Œ€ํ•œ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ์†”๋ฃจ์…˜์„ ์„ค๊ณ„ํ•˜์‹ญ์‹œ์˜ค.

๋ˆ„๊ตฐ๊ฐ€ ์ด ์ค‘ ํ•˜๋‚˜๋ฅผ ๋„์™€์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด ๊ธฐ๊บผ์ด ๋„์›€์„ ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค. NNBD ์ „ํ™˜์„ ๋จผ์ € ์ž‘์—…ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ณง ์ด ๋ฌธ์ œ์— ๋„๋‹ฌํ•  ๊ฒƒ ๊ฐ™์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@rrousselGit ๋ฌผ๋ก , ์ €๋Š” ๋งŽ์€ ์œ„์ ฏ์ด ํ™”๋ฉด ์ฃผ์œ„๋ฅผ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋Š” ์•ฑ์„ ๋งŒ๋“ค๊ณ  ์žˆ์œผ๋ฉฐ( Box es๋ผ๊ณ  ๋ถ€๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค), ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์›€์ง์ผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋”ฐ๋ผ์„œ ์ตœ์†Œํ•œ ๊ฐ Box ์— ๋Œ€ํ•ด ํ•˜๋‚˜์˜ AnimationController ). ๋‹ค์Œ์€ ์—ฌ๋Ÿฌ ์œ„์ ฏ ๊ฐ„์— ๊ณต์œ ๋˜๋Š” ๋‹จ ํ•˜๋‚˜์˜ AnimationController๋กœ ๋งŒ๋“  ๋ฒ„์ „์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฏธ๋ž˜์—๋Š” ๊ฐ ์œ„์ ฏ์„ ๋…๋ฆฝ์ ์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋งž์ถค ์Šคํฌ๋กค ํœ  ํšจ๊ณผ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CupertinoPicker ๊ตฌํ˜„๊ณผ ๊ฐ™์€ ๋ณต์žกํ•œ ๋ณ€ํ™˜์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. .

Stack์—๋Š” FloatingActionButton์„ ํด๋ฆญํ•  ๋•Œ ์œ„์•„๋ž˜๋กœ ์›€์ง์ด๋Š” ์„ธ ๊ฐœ์˜ ์ƒ์ž๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

void main(List<String> args) => runApp(const App());

class App extends HookWidget {
  const App({Key key});

  static const Duration duration = Duration(milliseconds: 500);
  static const Curve curve = Curves.easeOutBack;

  <strong i="11">@override</strong>
  Widget build(BuildContext context) {
    final AnimationController controller =
        useAnimationController(duration: duration);
    final Animation<double> animation = Tween<double>(
      begin: 0,
      end: 300,
    )
        .chain(
          CurveTween(
            curve: curve,
          ),
        )
        .animate(controller);
    final ValueNotifier<bool> isDown = useState<bool>(false);
    final ValueNotifier<int> numBoxes = useState<int>(3);

    return MaterialApp(
      home: SafeArea(
        child: Scaffold(
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              if (!isDown.value) {
                controller.forward();
                isDown.value = true;
              } else {
                controller.reverse();
                isDown.value = false;
              }
            },
          ),
          body: AnimatedBuilder(
            animation: animation,
            builder: (_, __) => Boxes(
              numBoxes: numBoxes.value,
              animation: animation,
            ),
          ),
        ),
      ),
    );
  }
}

class Boxes extends StatelessWidget {
  Boxes({
    <strong i="12">@required</strong> this.numBoxes,
    <strong i="13">@required</strong> this.animation,
  });

  final int numBoxes;
  final Animation<double> animation;

  <strong i="14">@override</strong>
  Widget build(BuildContext context) {
    return Stack(
      children: List<Widget>.generate(
        numBoxes,
        (int index) => Positioned(
          top: (animation.value) + (index * (100 + 10)),
          left: (MediaQuery.of(context).size.width - 100) / 2,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
          ),
        ),
      ),
      // ],
    );
  }
}

์ด ๊ฒฝ์šฐ ๊ฐ ์ƒ์ž๋Š” ์ผ์ œํžˆ ์›€์ง์ด์ง€๋งŒ ์˜ˆ๋ฅผ ๋“ค์–ด ์ •๋ ฌ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์‹œ๊ฐํ™”๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ชฉ๋ก์—์„œ ์š”์†Œ๋ฅผ ์ด๋™ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋” ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ƒ์œ„ ์œ„์ ฏ์€ ๊ฐ Box ์œ„์น˜์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” AnimationControllers์™€ ์›€์ง์ž„์„ ๊ตฌ๋™ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” Box ๊ฐ€ ๊ฐ™์€ ํด๋ž˜์Šค์— ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•  ๋ฐฐ์—ด์„ ์œ ์ง€ํ•˜์—ฌ AnimationController๋ฅผ ํ†ต๊ณผํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Builder ๋˜๋Š” ๊ฐ Box ๊ฐ€ ์ž์ฒด AnimationController๋ฅผ ์œ ์ง€ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Box es์™€ ์ƒ์œ„ ์œ„์ ฏ์ด ๊ฐ™์€ ํด๋ž˜์Šค์— ์žˆ์ง€ ์•Š์€ ๊ฒฝ์šฐ ๊ฐ Box ๊ฐ€ AnimationController์—์„œ ์ „๋‹ฌ๋˜๋Š” ์ฒซ ๋ฒˆ์งธ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด AnimationController ๋ชฉ๋ก์„ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค๊นŒ์š”? ์ด๊ฒƒ์€ HookBuilder๋ฅผ ์‚ฌ์šฉํ•œ ์œ„์˜ ๋‹ต๋ณ€์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•  ๋•Œ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์ง€๋งŒ, ๋ง์”€ํ•˜์‹  ๋Œ€๋กœ ์ƒํƒœ๋ฅผ ํ•˜์œ„ ์œ„์ ฏ์œผ๋กœ ์ด๋™ํ•˜๊ณ  ๊ฐ Box useAnimationController ๋ฅผ ํ†ตํ•ด ์ž์ฒด AnimationController๋ฅผ ๊ฐ–๋„๋ก ์„ ํƒํ•˜๋ฉด , ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ฑ๋œ AnimationController๋ฅผ ๋ถ€๋ชจ ํด๋ž˜์Šค์— ๋…ธ์ถœํ•˜์—ฌ ๊ฐ ์ž์‹์— ๋Œ€ํ•œ ๋…๋ฆฝ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์กฐ์ •ํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

Vue์—์„œ๋Š” emit ํŒจํ„ด์„ ํ†ตํ•ด ์ด๋ฒคํŠธ๋ฅผ ๋ถ€๋ชจ์—๊ฒŒ ๋‹ค์‹œ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Flutter์—์„œ๋Š” ๋ถ€๋ชจ๊ฐ€ ์ „์—ญ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์ž์‹์ด ์ „์—ญ ์ƒํƒœ๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” Riverpod ๋˜๋Š” Rx์™€ ๊ฐ™์€ ๊ณ ๊ธ‰ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ? ์ƒํƒœ? ์ ์–ด๋„ ์ด์™€ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ์˜ˆ์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚ด ํ˜ผ๋ž€์„ ํ•ด๊ฒฐํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

@satvikpendem ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๋ช…ํ™•ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๋กœ ์ฐจ๋‹จํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ํ›„ํฌ ์—†์ด ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์–ด๋””์—์„œ ๋ง‰ํžˆ๊ธฐ ๋ณด๋‹ค๋Š” ๋ฌด์—‡์„ ํ•˜๋ ค๋Š”์ง€ ๋ช…ํ™•ํžˆ ์ดํ•ดํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋น ๋ฅธ ์ถ”์ธก์œผ๋กœ, ๋Œ€์‹  Interval ๊ณก์„ ์„ ์ฐพ๊ณ  ์žˆ๊ณ  ๋‹จ์ผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@rrousselGit ๋ฌผ๋ก ์ž…๋‹ˆ๋‹ค.

import 'package:flutter/material.dart';

void main(List<String> args) => runApp(const App());

class Animator {
  Animator({this.controller, this.animation});
  AnimationController controller;
  Animation<double> animation;
}

class App extends StatefulWidget {
  const App({Key key});

  static const Duration duration = Duration(milliseconds: 500);
  static const Curve curve = Curves.easeOutBack;

  <strong i="7">@override</strong>
  _AppState createState() => _AppState();
}

class _AppState extends State<App> with TickerProviderStateMixin {
  List<Animator> animators = [];
  bool isDown = false;
  int numBoxes = 3;

  <strong i="8">@override</strong>
  void initState() {
    for (int i = 0; i < numBoxes; i++) {
      final AnimationController c = AnimationController(
        duration: App.duration,
        vsync: this,
      );
      animators.add(
        Animator(
          controller: c,
          animation: Tween<double>(
            begin: 0,
            end: 300,
          )
              .chain(
                CurveTween(
                  curve: App.curve,
                ),
              )
              .animate(c),
        ),
      );
    }
    super.initState();
  }

  <strong i="9">@override</strong>
  void dispose() {
    for (int i = 0; i < numBoxes; i++) {
      animators[i].controller.dispose();
    }
    super.dispose();
  }

  <strong i="10">@override</strong>
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SafeArea(
        child: Scaffold(
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              if (!isDown) {
                for (final Animator animator in animators) {
                  animator.controller.forward();
                }
                setState(() {
                  isDown = true;
                });
              } else {
                for (final Animator animator in animators) {
                  animator.controller.reverse();
                }
                setState(() {
                  isDown = false;
                });
              }
            },
          ),
          body: Stack(
            children: List<Box>.generate(
              numBoxes,
              (int index) => Box(
                index: index,
                animation: animators[index].animation,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class Box extends StatelessWidget {
  Box({
    <strong i="11">@required</strong> this.animation,
    <strong i="12">@required</strong> this.index,
  });

  final int index;
  final Animation<double> animation;

  <strong i="13">@override</strong>
  Widget build(BuildContext context) {
    return Positioned(
      top: (animation.value) + (index * (100 + 10)),
      left: (MediaQuery.of(context).size.width - 100) / 2,
      child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
      ),
    );
  }
}

๋‚˜๋Š” ์‹ค์ œ๋กœ ๊ฐ ์œ„์ ฏ์— ๋Œ€ํ•ด ํ•˜๋‚˜์”ฉ ์—ฌ๋Ÿฌ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๊ณ  ์ž์ฒด ์ง€์† ์‹œ๊ฐ„, ๊ณก์„  ๋“ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์œ„์˜ ์ฝ”๋“œ์—๋Š” ๋‚ด๊ฐ€ ํŒŒ์•…ํ•  ์ˆ˜ ์—†๋Š” ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊น”๋”ํ•˜๊ฒŒ ์• ๋‹ˆ๋ฉ”์ด์…˜๋˜์–ด์•ผ ํ•˜์ง€๋งŒ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ 3๊ฐœ์˜ ์ƒ์ž๋ฅผ ์œ„์•„๋ž˜๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๊ฐ๊ฐ์ด ๋™์ผํ•œ ๊ณก์„ ์„ ๊ฐ–๋Š” ๋Œ€์‹ ์— ๊ฐ๊ฐ ๋‹ค๋ฅธ ๊ณก์„ ์„ ์ œ๊ณตํ•˜๊ฑฐ๋‚˜ ์ด์ „ ๊ฒƒ๋ณด๋‹ค ์ง€์† ์‹œ๊ฐ„์ด ๋” ๊ธธ๊ฑฐ๋‚˜ ์งง์€ 100๊ฐœ์˜ ์ƒ์ž๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ง์ˆ˜๋ฅผ ์œ„๋กœ ์˜ฌ๋ฆฌ๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ƒํ•œ ๊ฒƒ๋“ค์€ ๋‚ด๋ ค๊ฐ‘๋‹ˆ๋‹ค.

์ผ๋ฐ˜ Flutter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด initState ๋ฐ dispose ๋‘˜ ๋‹ค ๋ฃจํ”„๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€ ์•Š์œผ๋ฏ€๋กœ ์–ด๋–ป๊ฒŒ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ Box ํด๋ž˜์Šค๋ฅผ ๋ถ€๋ชจ ์œ„์ ฏ ์•ˆ์— ๋„ฃ๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค ๋‹จ๋‹จํžˆ ์บก์Šํ™”ํ•˜๊ณ  ์‹ถ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ƒ์œ„ ๋…ผ๋ฆฌ๋ฅผ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜์ง€๋งŒ ์˜ˆ๋ฅผ ๋“ค์–ด Box ๋ฅผ Box2 ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์‚ฌ ํ•ด์š”!
ํ›„ํฌ์— ํ•ด๋‹นํ•˜๋Š” @TimWhiting ์˜ repo์— ๊ท€ํ•˜์˜ ์˜ˆ๋ฅผ ํ‘ธ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.

TL;DR, ํ›„ํฌ(๋˜๋Š” ๋นŒ๋”)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ช…๋ นํ˜•์ด ์•„๋‹ˆ๋ผ ์„ ์–ธํ˜•์œผ๋กœ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•˜๋‚˜์˜ ์œ„์ ฏ์— ์ปจํŠธ๋กค๋Ÿฌ ๋ชฉ๋ก์ด ์žˆ๋Š” ๋Œ€์‹  ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ•ญ๋ชฉ์œผ๋กœ ์ด๋™ํ•˜๊ณ  ์•”์‹œ์  ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ช…๋ น์ ์œผ๋กœ ๊ตฌ๋™ํ•ฉ๋‹ˆ๋‹ค.

@rrousselGit ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ•œ ํ›„ ์ž ์‹œ ๋™์•ˆ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๊ตฌํ˜„์— ์–ด๋ ค์›€์„ ๊ฒช์—ˆ์ง€๋งŒ ์ด์ œ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ์œ„์—์„œ ๋งํ–ˆ๋“ฏ์ด ํ›„ํฌ๊ฐ€ ์œ ์šฉํ•œ ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋” ๋งค๋ ฅ์ ์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ๋Œ€์ƒ์ด ์žˆ๋Š” ๋ฒ„์ „์— ๋Œ€ํ•œ PR์„ ์—ด์—ˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๊ฐ๊ฐ์ด ๋™์ผํ•œ ๊ณก์„ ์„ ๊ฐ–๋Š” ๋Œ€์‹ ์— ๊ฐ๊ฐ ๋‹ค๋ฅธ ๊ณก์„ ์„ ์ œ๊ณตํ•˜๊ฑฐ๋‚˜ ์ด์ „ ๊ฒƒ๋ณด๋‹ค ์ง€์† ์‹œ๊ฐ„์ด ๋” ๊ธธ๊ฑฐ๋‚˜ ์งง์€ 100๊ฐœ์˜ ์ƒ์ž๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ง์ˆ˜๋ฅผ ์œ„๋กœ ์˜ฌ๋ฆฌ๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ƒํ•œ ๊ฒƒ๋“ค์€ ๋‚ด๋ ค๊ฐ‘๋‹ˆ๋‹ค.

์„ ์–ธ์  ๋ฒ„์ „์„ ๋งŒ๋“ค๋ ค๊ณ  ํ–ˆ์œผ๋‚˜ didUpdateWidget/Hook ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฐฉ์‹์ด ์ดํ•ด๊ฐ€ ์•ˆ ๋œ ๊ฒƒ ๊ฐ™์•„์„œ ์ž์‹ prop์ด ๋ถ€๋ชจ์—์„œ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ตฌ๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ท€ํ•˜์˜ ์ฝ”๋“œ๋กœ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋Š˜ ๋‚ด ์ฝ”๋“œ ๊ธฐ๋ฐ˜์—์„œ ์‹ค์ œ ์˜ˆ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์œผ๋ฏ€๋กœ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์ €๋Š” Firestore๋กœ ์ž‘์—…ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ๊ฐ StreamBuilder๋กœ ์ˆ˜ํ–‰ํ•  ๋ช‡ ๊ฐ€์ง€ ์ƒ์šฉ๊ตฌ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋‚˜๋งŒ์˜ ์‚ฌ์šฉ์ž ์ •์˜ ๋นŒ๋”๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ValueListenable๋กœ ์ž‘์—…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.์‚ฌ์šฉ์ž๊ฐ€ ๋ชฉ๋ก์„ ์žฌ์ •๋ ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Firestore์™€ ๊ด€๋ จ๋œ ๊ธˆ์ „์  ๋น„์šฉ์ƒ์˜ ์ด์œ ๋กœ ์ด๊ฒƒ์€ ๋งค์šฐ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค(๊ฐ ํ•ญ๋ชฉ์€ ์ž์ฒด ์ฃผ๋ฌธ์„ ์ €์žฅํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ๋Œ€์‹  ๋ชฉ๋ก์€ ์—ฐ๊ฒฐ๋œ ID์˜ ํ•„๋“œ๋กœ ์ €์žฅํ•ด์•ผ ํ•จ). ์ด๋Ÿฐ ์‹์œผ๋กœ ์ž ์žฌ์ ์œผ๋กœ ๋งŽ์€ ๋ˆ์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ์Šต๋‹ˆ๋‹ค.

return ClipRRect(
      borderRadius: BorderRadius.circular(CornerStyles.dialog),
      child: Scaffold(
        backgroundColor: state.theme.scaffoldBackgroundColor,
        body: FamilyStreamBuilder<DocumentSnapshot>(
          stream: state.listRef.snapshots(),
          builder: (context, AsyncSnapshot<DocumentSnapshot> documentSnapshot) {
            //When a list is updated, we need to update the listOrder
            state.updateListOrderFromSnapshot(documentSnapshot);
            return FamilyStreamBuilder<QuerySnapshot>(
                stream: state.itemsCollection.snapshots(),
                builder: (_, AsyncSnapshot<QuerySnapshot> itemsSnapshot) {
                  //Sort the list items by the idField on the list-doc
                  List<DocumentSnapshot> items = itemsSnapshot.data.documents;
                  state.handleDocsSync(items);
                  return ValueListenableBuilder(
                    valueListenable: state.listOrderNotifier,
                    builder: (_, List<String> listOrder, __) {
                      List<DocumentSnapshot> ordered = state.sortItems(items, listOrder);
                     //Set the firstCompleted item if we have one
                      state.firstCompletedItem = ordered
                          ?.firstWhere((element) => element.data[FireParams.kIsComplete] == true, orElse: () => null)
                          ?.documentID;
                      return _buildItemList(items, ordered);
                    },
                  );
                });
          },
        ),
      ),
    );

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์“ธ ์ˆ˜ ์žˆ๋‹ค๋ฉด ํ›จ์”ฌ ๋” ์‰ฝ๊ฒŒ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    DocumentSnapshot list = useFamilyStream(state.listRef.snapshots());
    List<DocumentSnapshot> items = useFamilyStream(state.itemsCollection.snapshots()).data.documents;
    List<String> listOrder = useValueListenable(state.listOrderNotifier);

    //When a list is updated, we need to update the listOrder
    state.updateListOrderFromSnapshot(list);

   //Sort the list items by the idField on the list-doc
    state.handleDocsSync(items);
    List<DocumentSnapshot> ordered = state.sortItems(items, listOrder);

    //Set the firstCompleted item if we have one
    state.firstCompletedItem = ordered
        ?.firstWhere((element) => element.data[FireParams.kIsComplete] == true, orElse: () => null)
        ?.documentID;

    return ClipRRect(
      borderRadius: BorderRadius.circular(CornerStyles.dialog),
      child: Scaffold(
          backgroundColor: state.theme.scaffoldBackgroundColor,
          body: _buildItemList(items, ordered)
      ));

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์„ธ๋ถ„ํ™”๋œ ์žฌ๊ตฌ์„ฑ๊ณผ ๊ด€๋ จ๋œ ์ตœ์ ํ™”๊ฐ€ ์†์‹ค๋˜์ง€๋งŒ ๋ชจ๋“  ์‹œ๊ฐ์  ์š”์†Œ๊ฐ€ ๋งจ ์•„๋ž˜ ๋ฆฌํ”„ ๋…ธ๋“œ์— ์žˆ๊ณ  ๋ชจ๋“  ๋ž˜ํผ๊ฐ€ ์ˆœ์ˆ˜ ์ƒํƒœ์ด๋ฏ€๋กœ ๋‹ค๋ฅธ IRL์„ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋งŽ์€ ์‹ค์ œ ์‹œ๋‚˜๋ฆฌ์˜ค์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ "X๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค"๋ผ๋Š” ์กฐ์–ธ์€ ํ˜„์‹ค์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Firebase์—๋Š” Streams๋ผ๋Š” ์—ฐ๊ฒฐ ๋ฐฉ๋ฒ•์ด ํ•˜๋‚˜๋งŒ ์žˆ๊ณ  ์ด ์†Œ์ผ“๊ณผ ๊ฐ™์€ ๋™์ž‘์„ ์›ํ•  ๋•Œ๋งˆ๋‹ค ์„ ํƒ์˜ ์—ฌ์ง€๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์„ธ๋ผ๋น„.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์„ธ๋ถ„ํ™”๋œ ์žฌ๊ตฌ์„ฑ๊ณผ ๊ด€๋ จ๋œ ์ตœ์ ํ™”๊ฐ€ ์†์‹ค๋˜์ง€๋งŒ ๋ชจ๋“  ์‹œ๊ฐ์  ์š”์†Œ๊ฐ€ ๋งจ ์•„๋ž˜ ๋ฆฌํ”„ ๋…ธ๋“œ์— ์žˆ๊ณ  ๋ชจ๋“  ๋ž˜ํผ๊ฐ€ ์ˆœ์ˆ˜ ์ƒํƒœ์ด๋ฏ€๋กœ ๋‹ค๋ฅธ IRL์„ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์—ฌ์ „ํžˆ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋…ธ๋“œ๊ฐ€ ์‹œ๊ฐ์ ์ธ์ง€ ์—ฌ๋ถ€๋Š” ์žฌ๊ตฌ์ถ• ๋น„์šฉ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์•„๋งˆ๋„ ๊ทธ ์˜ˆ๋ฅผ ๋‹ค๋ฅธ ์œ„์ ฏ์— ํฌํ•จ์‹œํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค. _buildItemList ๋Š” FamilyStreamBuilder ๋ฟŒ๋ฆฌ๋ฅผ ๋‘” ๋ถ€๋ถ„๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์œ„์ ฏ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์„ธ๋ถ„ํ™”๋œ ์žฌ๊ตฌ์ถ•์„ ์žƒ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์‹ค์ œ๋กœ ํ›„ํฌ๋Š” useMemoized ์‚ฌ์šฉํ•˜์—ฌ ์œ„์ ฏ ์ธ์Šคํ„ด์Šค๋ฅผ ์‰ฝ๊ฒŒ ์บ์‹œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ ์ด๋Ÿฌํ•œ ์ธก๋ฉด์„ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.

Tim์˜ repo์—๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์•„๋งˆ๋„ ๊ทธ ์˜ˆ๋ฅผ ๋‹ค๋ฅธ ์œ„์ ฏ์— ํฌํ•จ์‹œํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค. _buildItemList ๋Š” FamilyStreamBuilder ๋ฟŒ๋ฆฌ๋ฅผ ๋‘” ๋ถ€๋ถ„๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์œ„์ ฏ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ์ด ๋ณด๊ธฐ์—์„œ ์„ฑ๋Šฅ์— ๋Œ€ํ•œ ์šฐ๋ ค๊ฐ€ ์ „ํ˜€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ 100% ์ €๋Š” ์ด์™€ ๊ฐ™์€ ๋ฏธ์„ธ ์ตœ์ ํ™”๋ณด๋‹ค ์ฝ”๋“œ ์ง€์—ญ์„ฑ๊ณผ ์ผ๊ด€์„ฑ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ณด๊ธฐ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜(~avg 10์ดˆ๋‹น ํ•œ ๋ฒˆ) ๋ฐฑ์—”๋“œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ณ  ์—ด๋ฆฐ ๋ชฉ๋ก์„ ์‘์‹œํ•  ๋•Œ(๊ฑฐ์˜ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ)์—๋งŒ ๋‹ค์‹œ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ฃผ๋กœ ๋ชฉ๋ก์ธ ๋‹จ์ˆœํ•œ ๋ณด๊ธฐ์ผ ๋ฟ์ด๋ฉฐ ๋ชฉ๋ก์—๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์ž์ฒด ์ตœ์ ํ™”๊ฐ€ ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” build()๊ฐ€ ๊ธฐ์ˆ ์ ์œผ๋กœ ์–ธ์ œ๋“ ์ง€ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์‹ค์ œ๋กœ ์ž„์˜์˜ ์žฌ๊ตฌ์ถ•์€ ๋งค์šฐ ๋“œ๋ญ…๋‹ˆ๋‹ค.

์ด ๋ชจ๋“  ๋…ผ๋ฆฌ๊ฐ€ ํ•˜๋‚˜์˜ ์œ„์ ฏ์— ๊ทธ๋ฃนํ™”๋˜์–ด ์žˆ์œผ๋ฉด ์ด ๋ณด๊ธฐ์—์„œ ์ž‘์—…ํ•˜๊ณ  ๋””๋ฒ„๊ทธํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ฃผ๋กœ ๋‚˜์ค‘์— ๋‹ค์‹œ ๋Œ์•„์˜ฌ ๋•Œ ๋‚ด ์‚ถ์„ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๋…ธ๋ ฅ์ž…๋‹ˆ๋‹ค. :)

์ฃผ์˜ํ•ด์•ผ ํ•  ๋˜ ๋‹ค๋ฅธ ์‚ฌํ•ญ์€ ๊ตฌ๋ฉ์— ์žˆ๋Š” 3๊ฐœ์˜ ํด๋กœ์ €์™€ 16๊ฐœ์˜ ๊ณต๊ฐ„ ๋‚ด๋ถ€์— ํŠธ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ค‘์ฒฉ์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ๋นŒ๋“œ ๋ฐฉ๋ฒ•์—์„œ "๊ฐ•์ œ"๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ˆ, ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ณ„๋„์˜ ์œ„์ ฏ์œผ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋นŒ๋“œ ๋ฐฉ๋ฒ•์— ๋จธ๋ฌด๋ฅด์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ƒ์šฉ๊ตฌ๋ฅผ ์‹ค์ œ๋กœ _ํ•„์š”๋กœ ํ•˜๋Š” ์ˆ˜์ค€์œผ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค๋ฉด 2๊ฐœ์˜ ํŒŒ์ผ๋กœ ํ•ญ๋ชฉ์„ ๋ถ„ํ• ํ•˜๋Š” ๊ฐ€๋…์„ฑ ๋ฐ ์œ ์ง€ ๊ด€๋ฆฌ ๋ฒˆ๊ฑฐ๋กœ์›€์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (์„ฑ๋Šฅ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ์ข…์ข… ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค)

์ด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์ด๋ฏธ Stream Builder๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž ์ง€์ • ์œ„์ ฏ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ด ๋นŒ๋”์˜ ๊ตฌ์„ฑ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?? ์•ฝ๊ฐ„ ์˜ค๋ฒ„์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ๋ณด๊ธฐ์—์„œ ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ์ „ํ˜€ ์—†๊ธฐ ๋•Œ๋ฌธ์—

์˜ค ์„ฑ๋Šฅ์„ ์œ„ํ•ด ์œ„์ ฏ์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค. ๋นŒ๋”๊ฐ€ ์ด๋ฏธ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€๋…์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์„ ์œ„ํ•ด ๋ฆฌํŒฉํ† ๋งํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด "์˜ฌ๋ฐ”๋ฅธ" ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ฝ”๋“œ๋ฅผ ๊ตฌ์กฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋งํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์–ด์จŒ๋“  ๊ทธ๊ฒƒ์€ ์—ฌ๊ธฐ๋„ ์ €๊ธฐ๋„ ์•„๋‹ˆ๋‹ค.

๊ตฌ๋ฉ์— 3๊ฐœ์˜ ํด๋กœ์ €์™€ 16๊ฐœ์˜ ๊ณต๊ฐ„์ด ์žˆ๋Š” ๋‚ด๋ถ€์— ํŠธ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•  ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ๋ณด๋‹ค ๋” ๋„“์€ ๋ชจ๋‹ˆํ„ฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ... :-/

๊ทธ๋Ÿฐ ๋‹ค์Œ 2๊ฐœ์˜ ํŒŒ์ผ๋กœ ํ•ญ๋ชฉ์„ ๋ถ„ํ• ํ•˜๋Š” ๊ฐ€๋…์„ฑ ๋ฐ ์œ ์ง€ ๊ด€๋ฆฌ ๋ฒˆ๊ฑฐ๋กœ์›€์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์œ„์ ฏ์„ ๊ฐ™์€ ํŒŒ์ผ์ธ FWIW์— ๋„ฃ๊ฒ ์Šต๋‹ˆ๋‹ค.

์–ด์จŒ๋“ , ์ด๊ฒƒ์€ ์ข‹์€ ์˜ˆ์ด๋ฉฐ ๋” ๋งŽ์€ ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๊ตฌ๋ฌธ์ด ๋‹ค๋ฅธ ํ•˜๋‚˜์˜ ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ๋ณด๋‹ค ๋” ๋„“์€ ๋ชจ๋‹ˆํ„ฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ... :-/

๋‚˜๋Š” ultrawide :D๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ dartfmt๋Š” ๋ถ„๋ช…ํžˆ ์šฐ๋ฆฌ ๋ชจ๋‘๋ฅผ 80์œผ๋กœ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ 16์„ ์žƒ๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์š” ๋ฌธ์ œ๋Š” ๋‚ด ์ง„์ˆ ์˜ ๋์ด },);});},),),); ๋ญ”๊ฐ€ ์—‰๋ง์ด ๋˜์—ˆ์„ ๋•Œ ์ •๋ง ์žฌ๋ฏธ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ํŽธ์ง‘ํ•  ๋•Œ๋งˆ๋‹ค ๋งค์šฐ ์กฐ์‹ฌํ•ด์•ผ ํ•˜๋ฉฐ swap with parent ์™€ ๊ฐ™์€ ์ผ๋ฐ˜์ ์ธ IDE ๋„์šฐ๋ฏธ๊ฐ€ ์ž‘๋™์„ ๋ฉˆ์ถฅ๋‹ˆ๋‹ค.

์œ„์ ฏ์„ ๊ฐ™์€ ํŒŒ์ผ์ธ FWIW์— ๋„ฃ๊ฒ ์Šต๋‹ˆ๋‹ค.

100%์ง€๋งŒ ์—ฌ์ „ํžˆ ๋‹จ์ผ ํŒŒ์ผ์—์„œ ์ˆ˜์ง์œผ๋กœ ์ ํ”„ํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€ ๊ด€๋ฆฌํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๋ถˆ๊ฐ€ํ”ผํ•˜์ง€๋งŒ ๊ฐ€๋Šฅํ•˜๋ฉด ์ค„์ด๊ณ  'ํ•จ๊ป˜ ํ•˜๋Š” ๊ฒƒ'์„ ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ์ •์ ์œผ๋กœ, ๊ธฐ๋ณธ ๋ชฉ๋ก์„ ์ž์ฒด ์œ„์ ฏ์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋”๋ผ๋„(๋‚ด ์ƒ๊ฐ์—๋Š” ์ค‘์ฒฉ๋œ ๋นŒ๋“œ ๋ฉ”์„œ๋“œ๋ณด๋‹ค ์ฝ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค) ์ƒ์œ„ ์œ„์ ฏ์— ์ค‘์ฒฉ๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋“ค์–ด์™€์„œ ๋ชจ๋“  ๋…ผ๋ฆฌ๋ฅผ ํ•œ ๋ˆˆ์— ์ดํ•ดํ•˜๊ณ  _MyListView() ์œ„์ ฏ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ณด๊ณ  ๋ฐ”๋กœ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ฃผ๋ณ€ ์ปจํ…์ŠคํŠธ๋ฅผ ์ดํ•ดํ•œ๋‹ค๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ƒ๋Œ€์ ์œผ๋กœ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ ์ข…์†์„ฑ์„ ์ถ”๊ฐ€/์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํ™•์žฅ์ด ๋งค์šฐ ์ž˜ ๋ฉ๋‹ˆ๋‹ค.

dartfmt๋Š” ๋ถ„๋ช…ํžˆ ์šฐ๋ฆฌ ๋ชจ๋‘๋ฅผ 80์œผ๋กœ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ๋ง์€, ๊ทธ๊ฒƒ์ด ๋‚ด๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ dartfmt๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ด์œ  ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ ์‚ฌ์šฉํ•  ๋•Œ 120 ๋˜๋Š” 180์ž๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค...

์—ฌ๊ธฐ์—์„œ์˜ ๊ฒฝํ—˜์€ ์™„์ „ํžˆ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์‹ค ์ €๋„ ํ•˜๋ฃจ ์ข…์ผ 120์ž…๋‹ˆ๋‹ค. :) ํ•˜์ง€๋งŒ pub.dev๋Š” 80์œผ๋กœ ํฌ๋งท๋˜์ง€ ์•Š์€ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ ๊ทน์ ์œผ๋กœ ๋‹ค์šด๋ ˆ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ €๋Š” ์ด ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ๋•Œ ์ €(์šฐ๋ฆฌ)๊ฐ€ ์†Œ์ˆ˜๋ผ๋Š” ์ธ์ƒ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฑด ๋ง๋„ ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์„ ๊ณ ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

pub.dev๋Š” dartfmt๋ฅผ ์กด์ค‘ํ•˜์ง€ ์•Š๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ํ‰๊ฐ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ ์ˆ˜ ํŽ˜์ด์ง€์—๋Š” ๋Œ“๊ธ€๋งŒ ํ‘œ์‹œ๋˜์ง€๋งŒ ์ ์ˆ˜์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ํ‹€๋ฆผ์—†์ด dartfmt์—๋Š” ๋ผ์ธ ๊ธธ์ด๋ณด๋‹ค ๋” ๋งŽ์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค„ ๊ธธ์ด๊ฐ€ ๋„ˆ๋ฌด ํฌ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—ฌ๋Ÿฌ ์ค„์—์„œ ๋” ์ฝ๊ธฐ ์‰ฌ์šด ๊ฒƒ์ด ํ•œ ์ค„๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

object
  ..method()
  ..method2();

๋‹ค์Œ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

object..method()..method2();

๋‚˜๋Š” ์ด๊ฒƒ์„๋ณด๊ณ ์žˆ๋‹ค?
image
๋ฌธ์ œ์˜ ํŒจํ‚ค์ง€: https://pub.dev/packages/sized_context/score

ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค. ๊ณต๊ธ‰์ž๊ฐ€ ํ•œ๋™์•ˆ dartfmt๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์ „์—๋Š” ํ™•์‹คํžˆ ๊ทธ๋ ‡์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
์ •์ •ํ•ฉ๋‹ˆ๋‹ค.

๋„ค, ํ™•์‹คํžˆ ์ƒˆ๋กœ์šด ๋™์ž‘์ž…๋‹ˆ๋‹ค. ์ œ๊ฐ€ ์ž‘๋…„ ๋ด„์— ์ฒ˜์Œ ๊ฒŒ์‹œํ–ˆ์„ ๋•Œ ๋ชจ๋“  ์ƒ์ž์— ์ฒดํฌ ํ‘œ์‹œ๋ฅผ ํ–ˆ๋Š”์ง€ ํ™•์ธํ–ˆ๊ณ  dartfmt๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ชจ๋“  ๋…ผ์˜๊ฐ€ ๋๋‚˜๋ฉด Flutter์—์„œ ํ›„ํฌ์™€ ๊ฐ™์€ ์†”๋ฃจ์…˜์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ง€์›์„ ๋ณผ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. useHook ๋˜๋Š” use Hook ๋˜๋Š” flutter ํŒ€์ด ์ž์‹ ์˜ ๊ธฐ๋Šฅ์ด React์™€ ๊ฐ™์ง€ ์•Š๋‹ค๊ณ  ๋Š๋‚„ ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ ๐Ÿ˜๐Ÿคทโ€โ™‚๏ธ

final controller = useAnimationController(duration: Duration(milliseconds: 800)); ์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
kotlin/swift์—์„œ ๋ณต์‚ฌํ•œ Darts์˜ ์ƒˆ ํ”„๋กœ๊ทธ๋žจ ๊ธฐ๋Šฅ _Extension_์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ทธ ๊ตฌ๋ฌธ์„ ์•„๋ฆ„๋‹ต๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋” ์ข‹์ง€ ์•Š์Šต๋‹ˆ๊นŒ?

final controller = AnimationController.use(duration: Duration(milliseconds: 800)); ์™€ ๊ฐ™์€ ๊ฒƒ
์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด flutter/dart ํŒ€์ด ํ˜„์žฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ตฌ๋ฌธ useHook ๋Œ€์‹  use Hook ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์„ ๋•Œ ํ•ด๋‹น ํ™•์žฅ ํ•จ์ˆ˜์— Annotation ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋„๋ก ์ฝํ˜”์Šต๋‹ˆ๋‹ค.
final controller = use AnimationController(duration: Duration(milliseconds: 800));

๋˜ํ•œ const ๋ฐ new ์™€ ๊ฐ™์ด const use ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ์ดํ•ด ๊ฐ€๋Šฅ/์˜๋ฏธ ์žˆ์Šต๋‹ˆ๋‹ค.
new Something
const Something
use Something

๊ทธ ๊ถŒ์žฅ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ๋ณด๋„ˆ์Šค๋กœ, ๋งˆ์นจ๋‚ด ์ƒ์„ฑ์ž/์ƒ์„ฑ๊ธฐ ํ•จ์ˆ˜๋„ ์ œ์•ˆ๋œ Annotation ์—์„œ ์‚ฌ์šฉ/์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ผ๋ถ€ ์‚ฌ์šฉ์ž ์ •์˜๊ฐ€ ํฌํ•จ๋œ dart ์ปดํŒŒ์ผ๋Ÿฌ๋Š” use ํ‚ค์›Œ๋“œ๋ฅผ ์ง€์›ํ•˜๋„๋ก ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋„ˆ๋ฌด ์•„๋ฆ„๋‹ต๊ณ  ํ”Œ๋Ÿฌํ„ฐ/๋‹คํŠธ ์ „์šฉ ๊ธฐ๋Šฅ ๐Ÿ˜‰

https://github.com/TimWhiting/local_widget_state_approaches/tree/master/lib/stateful ์˜ ์˜ˆ๊ฐ€ ์ด์ œ ์‚ฌ๋žŒ๋“ค์ด ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋Œ€ํ‘œํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๊นŒ?

๋‚˜๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์–ด๋–ป๊ฒŒ ๋Š๋ผ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ๊ฑฐ๊ธฐ์— ์–ด๋Š ์ •๋„ ํ‘œํ˜„๋˜์–ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น ์ €์žฅ์†Œ์—์„œ ์ค‘๊ฐ„ ์†”๋ฃจ์…˜์„ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ›„ํฌ์ฒ˜๋Ÿผ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ํ•จ์ˆ˜ ํ˜ธ์ถœ์˜ ์ˆœ์„œ์— ์˜์กดํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋ฃจํ”„๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. StatefulWidget์„ ์ง์ ‘ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋ฏน์Šค์ธ๊ณผ ํ‚ค๋กœ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„๋˜๋Š” ์ƒํƒœ ์ €์žฅ ์†์„ฑ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์„ ๊ถ๊ทน์ ์ธ ํ•ด๊ฒฐ์ฑ…์œผ๋กœ ํ™๋ณดํ•˜๋ ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋‘ ์ ‘๊ทผ ๋ฐฉ์‹ ์‚ฌ์ด์˜ ์ค‘๊ฐ„ ์ง€์ ์œผ๋กœ ํ™๋ณดํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ €๋Š” ์ด๊ฒƒ์„ lifecycleMixin ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๊ณ  ๋ถˆ๋ €์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ๋…ผ์˜ํ•œ LateProperty ์ ‘๊ทผ ๋ฐฉ์‹๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•˜์ง€๋งŒ ์ฃผ์š” ์ฐจ์ด์ ์€ ๊ตฌํ˜„๋œ ์ˆ˜๋ช… ์ฃผ๊ธฐ๊ฐ€ ๋” ๋งŽ๊ณ  ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. (์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ถ€๋ถ„์—์„œ ๋‚˜๋Š” initState ์ด์™ธ์˜ ์œ„์ ฏ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๊ณ  ๋งŽ์ด ํ๊ธฐํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฑฐ๊ธฐ์„œ ์™„์ „ํžˆ ์—‰๋ง์ด ๋˜์—ˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).

๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค.

  1. ๋Ÿฐํƒ€์ž„ ํŽ˜๋„ํ‹ฐ๊ฐ€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค.
  2. ๋นŒ๋“œ ๊ฒฝ๋กœ์— ์ƒํƒœ๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๊ด€๋ฆฌํ•˜๋Š” ๋กœ์ง/ํ•จ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค(๋นŒ๋“œ๋Š” ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ๋งŒ ํ•  ์ˆ˜ ์žˆ์Œ).
  3. ๋นŒ๋”๋ฅผ ํ†ตํ•ด ์žฌ๊ตฌ์ถ•์„ ์ตœ์ ํ™”ํ•  ๋•Œ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๊ด€๋ฆฌ๊ฐ€ ๋” ๋ช…ํ™•ํ•ด์ง‘๋‹ˆ๋‹ค. (๊ทธ๋Ÿฌ๋‚˜ ์ž‘์€ ์ƒํƒœ ๋น„ํŠธ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ๊ตฌ์„ฑ์„ฑ์„ ํฌ์ƒํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.)
  4. ์ƒํƒœ ๋น„ํŠธ ์ƒ์„ฑ์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํŠน์ • ๋ฐฉ์‹์œผ๋กœ ์ƒ์„ฑ ๋ฐ ํ๊ธฐํ•ด์•ผ ํ•˜๋Š” ๊ณตํ†ต ์ƒํƒœ ๋น„ํŠธ๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ณ ์œ ํ•œ ์ฝ”๋“œ์— ์ƒ์šฉ๊ตฌ๊ฐ€ ์ ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ํ›„ํฌ์™€ ๋น„๊ตํ•˜์—ฌ ์ด ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋งˆ์Œ์— ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  1. ํ›„ํฌ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ž‘์—…์„ ํฌํ•จํ•˜๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.
  2. ๋‹น์‹ ์€ ๊ณ ์œ ์˜ ํŠน์„ฑ์„ ์‹๋ณ„ํ•˜๊ธฐ์œ„ํ•œ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. (๋”ฐ๋ผ์„œ ์ผ๋ถ€ ์ƒํƒœ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋กœ์ง์„ ๊ตฌ์„ฑํ•  ๋•Œ ์ƒํƒœ์˜ ๊ฐ ๋ถ€๋ถ„์„ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ํ‚ค์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ‚ค๋ฅผ ํ•„์ˆ˜ ์œ„์น˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋˜์ง€๋งŒ, ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ๊ณ ์œ  ID).
  3. ๊ณตํ†ต ์ƒํƒœ ๋น„ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํ™•์žฅ์„ ๋งŽ์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ™•์žฅ์€ IDE์—์„œ ์ž๋™์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  4. ๋‹ค๋ฅธ ์œ„์ ฏ์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ํ˜ผํ•ฉํ•˜๊ฑฐ๋‚˜ ๋ช…์‹œ์ ์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ  ์œ„์ ฏ ๊ฐ„์— ์•ก์„ธ์Šคํ•˜๋ฉด ์ž์‹ ์„ ์—‰๋ง์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  5. ๋นŒ๋” ๊ตฌ๋ฌธ์ด ์•ฝ๊ฐ„ ์ด์ƒํ•ด์„œ ์ƒ์„ฑ๋œ ์ƒํƒœ๊ฐ€ ๋นŒ๋“œ ํ•จ์ˆ˜์˜ ๋ฒ”์œ„์— ์žˆ์ง€๋งŒ ๋นŒ๋“œ ํ•จ์ˆ˜๋Š” ์ˆœ์ˆ˜ํ•˜๊ฒŒ ๋‚จ๊ฒจ๋‘ก๋‹ˆ๋‹ค.
  6. ์•„์ง ๋ชจ๋“  ์˜ˆ์ œ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ๋‹ค๋ฃจ์ง€ ๋ชปํ•˜๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์นด์šดํ„ฐ ์˜ˆ.
์• ๋‹ˆ๋ฉ”์ด์…˜ ์นด์šดํ„ฐ ์˜ˆ

๋ผˆ๋Œ€
์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๊ตฌ์„ฑ ๋…ผ๋ฆฌ์˜ ๊ณตํ†ต ๋น„ํŠธ

์‹œ๊ฐ„์ด ์–ผ๋งˆ๋‚˜ ๋‚จ์•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋Œ€ํ•™์› ๊ณต๋ถ€๋Š” ํ•ญ์ƒ ์ €๋ฅผ ๋ฐ”์˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์žˆ์ง€๋งŒ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. @rrousselGit ์ด๊ฒƒ์ด ํ›„ํฌ์— ์–ผ๋งˆ๋‚˜ ๊ฐ€๊น์Šต๋‹ˆ๊นŒ? ์žฌ์‚ฌ์šฉ์„ฑ ๋˜๋Š” ๊ตฌ์„ฑ ๊ฐ€๋Šฅ์„ฑ์— ๋ช…๋ฐฑํ•œ ๊ตฌ๋ฉ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚ด ์†”๋ฃจ์…˜์„ ํ™๋ณดํ•˜๋ ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ค‘๊ฐ„ ์ง€์ ์—์„œ ๊ธ์ •์ ์ธ ํ† ๋ก ์„ ์žฅ๋ คํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋ˆ„๋ฝ๋œ ์‚ฌํ•ญ์ด๋‚˜ ์ด ์†”๋ฃจ์…˜์ด ์ œ๊ณตํ•˜๋Š” ์‚ฌํ•ญ์— ๋Œ€ํ•ด ๋™์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์•ž์œผ๋กœ ์ข‹์€ ์ง„์ „์„ ์ด๋ฃฐ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@TimWhiting ์ด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ์ฃผ์š” ๋ฌธ์ œ๋Š” ๊ฒฌ๊ณ ์„ฑ ๋ถ€์กฑ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํฐ ๋™์ธ์€ ๊ฐ„๊ฒฐํ•œ ํ˜•ํƒœ๋กœ ๊ฑด์ถ•์—…์ž์˜ ์‹ ๋ขฐ์„ฑ์— ๋Œ€ํ•œ ํ•„์š”์„ฑ์ž…๋‹ˆ๋‹ค. ๋งค์ง id์™€ ์ˆ˜๋ช… ์ฃผ๊ธฐ์—์„œ ์ถฉ๋Œํ•˜๋Š” ๊ธฐ๋Šฅ์€ ๋ชจ๋‘ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์œ„ํ•œ ์ƒˆ๋กœ์šด ๋ฒกํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๋ฉฐ, ์ฝ๊ธฐ์—๋Š” ๊ฝค ๋ถˆ์พŒํ•˜์ง€๋งŒ ์ ์–ด๋„ ์šฐ๋ฆฌ๋Š” ๊ทธ๋“ค์ด 100๊ฐœ๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ํŒ€์— ๊ณ„์† ๊ถŒ์žฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. % ๋ฒ„๊ทธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์˜ˆ์ œ์™€ ๊ด€๋ จํ•˜์—ฌ ์—ฌ์ „ํžˆ ์™„๋ฒฝํ•œ ์˜ˆ์ œ๋Š” ์œ„์ ฏ์— ์—ฐ๊ฒฐ๋œ ๊ธฐ๊ฐ„ ๊ฐ’๊ณผ ํ•จ๊ป˜ AnimationController๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ณ  ์นœ์ˆ™ํ•˜๊ฒŒ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ณด๋‹ค ๋” ๋‚œํ•ดํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒ์šฉ๊ตฌ์— ๋Œ€ํ•œ ์™„๋ฒฝํ•œ ์ž‘์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์ด๋ฉฐ, ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, ๋ชจ๋“  ์†”๋ฃจ์…˜์€ ์—ฌ๋Ÿฌ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋Šฅ๋ ฅ์œผ๋กœ ์‰ฝ๊ฒŒ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ์€ ์ด์™€ ๋™์ผํ•œ ์‚ฌ์šฉ '์ƒํƒœ ์ €์žฅ ์ปจํŠธ๋กค๋Ÿฌ' ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ๋ณ€ํ˜•์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. initState์—์„œ X๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  dispose ์ƒํƒœ์—์„œ Y๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ์ข…์†์„ฑ์ด ๋ณ€๊ฒฝ๋˜๋ฉด Z๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. X, Y, Z๊ฐ€ ๋ฌด์—‡์ธ์ง€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@rrousselGit ์ด ์—ฌ๊ธฐ์— ์•ฝ๊ฐ„์˜ ํ†ต์ฐฐ๋ ฅ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋˜๋Š” ํ˜„์žฌ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ํ›„ํฌ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. 80%๋Š” ์ŠคํŠธ๋ฆผ๊ณผ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ์‚ฌ๋žŒ๋“ค์ด ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€ ์•„๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ์˜ ์ผ๋ถ€๋ฅผ ์žฌ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จํ•˜์—ฌ ๋นŒ๋”๋Š” ์–ด์จŒ๋“  ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด ์ž‘์—…์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์ƒํƒœ ์ €์žฅ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์›ํ•˜๋Š” ๊ฒฝ์šฐ ์ƒํƒœ ๋น„์ €์žฅ ๋ Œ๋”๋Ÿฌ์— ์‰ฝ๊ฒŒ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋ชจ๋“  Transition ํด๋ž˜์Šค ์•ˆ๋…•ํ•˜์„ธ์š”).

์šฐ๋ฆฌ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ:

var anim = get AnimationController();
return Column(
  _someExpensiveBuildMethod(),
  FadeTransition(opacity: anim, child: ...)
)

์šฐ๋ฆฌ๋Š” ํ•ญ์ƒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

var foo = get ComplicatedThingController();
return Column(
  _someExpensiveBuildMethod(),
  ComplicatedThing(controller: foo, child: ...)
)

@esDotDev ํ‚ค์™€ ๋นŒ๋” ๊ตฌ๋ฌธ์ด lifecycleMixin ์ ‘๊ทผ ๋ฐฉ์‹์˜ ์ฃผ์š” ๋‹จ์ ์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ด€๋ จ ์ œํ•œ ์‚ฌํ•ญ์ด ์žˆ๋Š” ํ›„ํฌ ์Šคํƒ€์ผ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋ณ€์ˆ˜ ์„ ์–ธ์„ ์ƒํƒœ ๋น„ํŠธ์™€ ์ˆ˜๋ช… ์ฃผ๊ธฐ์™€ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ์–ธ์–ด ๋ณ€๊ฒฝ์„ ์ œ์™ธํ•˜๊ณ ๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ๊ณ„์† ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋” ๋‚˜์€ ์†”๋ฃจ์…˜์ด ๋‚˜์˜ค์ง€ ์•Š๋Š” ํ•œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ž์ฒด ์ œํ•œ์ด ์žˆ์ง€๋งŒ ํ›„ํฌ์˜ ์ œํ•œ์„ ์ข‹์•„ํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋Š” ํฅ๋ฏธ๋กœ์šด ๋Œ€์•ˆ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

https://github.com/TimWhiting/local_widget_state_approaches/tree/master/lib/stateful ์˜ ์˜ˆ๊ฐ€ ์ด์ œ ์‚ฌ๋žŒ๋“ค์ด ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋Œ€ํ‘œํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๊นŒ?

์†”์งํžˆ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.
๋‚˜๋Š” _์˜ˆ_๋ผ๊ณ  ๋งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์ด๋Ÿฌํ•œ ์˜ˆ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด์„ํ•  ๊ฒƒ์ธ๊ฐ€์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ์—์„œ ์šฐ๋ฆฌ๋Š” ์„œ๋กœ๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์—ญ์‚ฌ๊ฐ€ ์žˆ์–ด์„œ ๋‹ค์‹œ๋Š” ์ด๋Ÿฐ ์ผ์ด ์ผ์–ด๋‚˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์žฅ๋‹ดํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋ถ€๋ถ„์ ์œผ๋กœ ๋‚ด๊ฐ€ ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์‹ซ์–ดํ•˜๊ณ  ๋Œ€์‹  ๊ทœ์น™ ์ง‘ํ•ฉ์„ ์ถ”์ถœํ•˜๋„๋ก ์ œ์•ˆํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.
์˜ˆ๋Š” ์ฃผ๊ด€์ ์ด๊ณ  ์—ฌ๋Ÿฌ ์†”๋ฃจ์…˜์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ๊ทธ ์ค‘ ์ผ๋ถ€๋Š” ๋” ๊ด‘๋ฒ”์œ„ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@rrousselGit ์ด ์—ฌ๊ธฐ์— ์•ฝ๊ฐ„์˜ ํ†ต์ฐฐ๋ ฅ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋˜๋Š” ํ˜„์žฌ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ํ›„ํฌ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. 80%๋Š” ์ŠคํŠธ๋ฆผ๊ณผ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ์‚ฌ๋žŒ๋“ค์ด ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€ ์•„๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋งค์šฐ ๋™์งˆ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

useStream ๋ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๊ฐ€์žฅ ์ ๊ฒŒ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • useStream์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์•„ํ‚คํ…์ฒ˜์— ๋”ฐ๋ผ ๋” ๋‚˜์€ ๋™๋“ฑ๋ฌผ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. context.watch , useBloc , useProvider , ...
  • ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“œ๋Š” ๋ฐ ์‹œ๊ฐ„์„ ํ• ์• ํ•˜๋Š” ์‚ฌ๋žŒ์€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฑฐ์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์•„๋‹ˆ๋ฉฐ TweenAnimationBuilder ๋‹ค๋ฅธ ์•”์‹œ์ ์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜๋œ ์œ„์ ฏ์ด ํ•„์š”์˜ ํฐ ๋ถ€๋ถ„์„ ์ฐจ์ง€ํ•ฉ๋‹ˆ๋‹ค.
    flutter_hooks์— useImplicitlyAnimatedInt ํ›„ํฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@esDotDev lifecycleMixin ์ ‘๊ทผ ๋ฐฉ์‹์—์„œ ํ‚ค/ID์˜ ํ•„์š”์„ฑ์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๋นŒ๋” ๊ตฌ๋ฌธ์—์„œ๋Š” ์—ฌ์ „ํžˆ ์•ฝ๊ฐ„ ์–ด์ƒ‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฒฐ๊ตญ์—๋Š” ๊ทธ๊ฒƒ์ด ๋„์›€์ด ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๊ฒช๊ณ  ์žˆ๋Š” ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ๋Š” ์œ ํ˜• ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ํŠน์ • ๋ฐฉ์‹์œผ๋กœ ์ผ์„ ๋˜์ง€๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์•„๋งˆ๋„ ์ฃผ์˜ ๊นŠ์€ ์บ์ŠคํŒ…์ด๋‚˜ ์œ ํ˜• ์‹œ์Šคํ…œ ์ˆ™๋‹ฌ์ด ํ•„์š”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ผ์ดํ”„์‚ฌ์ดํด์„ ํ˜ผํ•ฉํ•˜๋Š” ํ•œ, ์•ก์„ธ์Šคํ•˜๋ ค๋Š” ํŠน์ • ์ƒํƒœ๊ฐ€ ํ•ด๋‹น ์œ„์ ฏ์˜ ๋ผ์ดํ”„์‚ฌ์ดํด์—์„œ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ๋ช‡ ๊ฐ€์ง€ ํ•ฉ๋ฆฌ์ ์ธ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋˜๋Š” lifecyclebuilder ๋‚ด์—์„œ ๋นŒ๋”์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ์—๋งŒ ์•ก์„ธ์Šคํ•ด์•ผ ํ•˜๋Š” ๋ฆฐํŠธ์ž…๋‹ˆ๋‹ค.

Remi ๋•๋ถ„์— ๋†€๋ž์Šต๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด Animation์„ ๋งค์šฐ ์ž์ฃผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”์–ด์— ์žˆ๋Š” ๋Œ€๊ทœ๋ชจ ์ „ํ™˜ ์œ„์ ฏ ๋ชจ์Œ์„ ๊ตฌ๋™ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. .

์—ฌ์ „ํžˆ AnimatorController๊ฐ€ ์•”์‹œ์  ๋ฐ ๋ช…์‹œ์  ์œ„์ ฏ ์ œํ’ˆ๊ตฐ๊ณผ ํ•จ๊ป˜ ๋งค์šฐ ์ž˜ ์ œ๊ณต๋˜๊ณ  ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์—ฌ์ „ํžˆ '์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ  ์œ„์ ฏ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์—ฐ๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ'์˜ ํ›Œ๋ฅญํ•œ ์˜ˆ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•ด๊ฒฐํ•ด์•ผ ํ•  ๋ฌธ์ œ์˜ ์™„๋ฒฝํ•œ ์ž‘์€ ์˜ˆ๋กœ์„œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค(์‚ฌ์‹ค์€ Flutter์—์„œ 12๊ฐœ์˜ ์œ„์ ฏ์ด ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์™„์ „ํžˆ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค). ์šฐ๋ฆฌ ๋ชจ๋‘๋Š” ์ฝ˜ํ…์ธ ๊ฐ€ ์•„๋‹Œ ์•„ํ‚คํ…์ฒ˜์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ณ  ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด var anim = AnimationController.use(context, duration: widget.duration ?? _duration); ๊ฐ€ ์ผ๋“ฑ ์‹œ๋ฏผ์ด๋ผ๋ฉด ์ด๋Ÿฌํ•œ ์•”์‹œ์  ๋˜๋Š” ๋ช…์‹œ์  ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์‹ค์ œ๋กœ ์กด์žฌํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•ด ๋ณด์‹ญ์‹œ์˜ค. ์œ„์ ฏ์˜ ์ปจํ…์ŠคํŠธ ๋‚ด์—์„œ ์ƒํƒœ ์ €์žฅ ์‚ฌ๋ฌผ(AnimationController)์„ ์‰ฝ๊ฒŒ ํ•ฉ์„ฑํ•˜๋Š” ํ•ต์‹ฌ ๋ฌธ์ œ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋‘ ์ƒ์„ฑ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๋ณต์œผ๋กœ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. AnimatedBuilder + AnimatorController.use() ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ TAB ์€ ๊ฑฐ์˜ ๋ฌด์˜๋ฏธํ•ด์ง‘๋‹ˆ๋‹ค.

์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฃผ์œ„์— ์ƒ๊ฒจ๋‚œ ์—„์ฒญ๋‚œ ์–‘์˜ ์œ„์ ฏ์„ ๋ณด๋ฉด ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ํ•„์š”์„ฑ์„ ์ž˜ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ํ•ต์‹ฌ ์„ค์ •/ํ•ด์ œ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๋ฒˆ๊ฑฐ๋กญ๊ณ  ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šฐ๋ฏ€๋กœ 15๊ฐœ ์ด์ƒ์˜ ์œ„์ ฏ์ด ๋ชจ๋‘ ๋งค์šฐ ๊ตฌ์ฒด์ ์ธ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์€ ๋ช‡ ๊ฐ€์ง€๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒ์šฉ๊ตฌ๋ฅผ ๋ฐ˜๋ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŽ์€ ๊ฒฝ์šฐ์— ๊ณ ์œ ํ•œ ์ฝ”๋“œ ๋ผ์ธ.

์˜ˆ, ์šฐ๋ฆฌ ์ž์‹ ์˜ ์ƒํƒœ ์ €์žฅ ๋…ผ๋ฆฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜๋„ ์žˆ์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์‚ฌ์šฉ์˜ ๋ชจ๋“  ๋‹จ์ผ ์ˆœ์—ด์— ๋Œ€ํ•œ ์œ„์ ฏ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์–ผ๋งˆ๋‚˜ ๋ฒˆ๊ฑฐ๋กญ๊ณ  ์œ ์ง€ ๊ด€๋ฆฌ๊ฐ€ ๊ณจ์น˜ ์•„ํ”ˆ์ง€! ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์€ ์ƒํƒœ ์ €์žฅ ๊ฐœ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ํ›จ์”ฌ ๋” ์ข‹์œผ๋ฉฐ, ๋ Œ๋”๋ง์„ ์œ„ํ•œ ์ „์šฉ ์œ„์ ฏ์ด๋‚˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋นŒ๋”๋ฅผ ๋งŒ๋“ค๋ ค๋Š” ๊ฒฝ์šฐ ๋งจ ์œ„์— ๋ ˆ์ด์–ด๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์œ„์ ฏ๋ณด๋‹ค ๋‚ด ์•ฑ์—์„œ useAnimation ์™€ ๊ฐ™์€ ๊ฒƒ์„ ๋งŽ์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด AnimatedContainer์™€ ๊ฐ™์€ ์œ„์ ฏ์—์„œ ์ž˜ ์ง€์›๋˜์ง€ ์•Š๋Š” SpringAnimation์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ๋ชจ๋‘ Simulation ์ธ์ˆ˜๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ธฐ๋ฐ˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์•„๋‹Œ curve ๋ฐ duration ํ•˜์—ฌ ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

useAnimation ์ด์ƒ์œผ๋กœ ์ถ”์ƒํ™”๋ฅผ ๋งŒ๋“ค์—ˆ์ง€๋งŒ ์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜์—ฌ useSpringAnimation ๋ผ๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ํ›„ํฌ์— ์‚ฌ์šฉํ•œ ๋ž˜ํผ ์œ„์ ฏ์€ AnimatedContainer ์™€ ๋น„์Šทํ•˜์ง€๋งŒ @esDotDev ๋ผ๊ณ  ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ชจ๋“  ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ›จ์”ฌ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋…ผ๋ฆฌ๊ฐ€ ๋งŽ์ด ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. useSpringAnimation ๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ์• ๋‹ˆ๋ฉ”์ด์…˜ ์œ„์ ฏ์˜ ๋‚ด ์ž์‹ ์˜ ๋ฒ„์ „์„ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๋‚ด ํ”„๋กœ์ ํŠธ์— ๊ผญ ํ•„์š”ํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ›„ํฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ผ์ดํ”„ ์‚ฌ์ดํด ๋กœ์ง ์žฌ์‚ฌ์šฉ์˜ ํž˜์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, if var anim = AnimationController.use(context, duration: widget.duration ?? _duration); ๊ทธ๋“ค์€ ์ผ๋ฅ˜ ์‹œ๋ฏผ์ด์—ˆ๊ณ  ์ด๋Ÿฌํ•œ ์•”์‹œ์  ๋˜๋Š” ๋ช…์‹œ์  ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ์‹ค์ œ๋กœ ์กด์žฌํ•  ํ•„์š”๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ์œ„์ ฏ์˜ ์ปจํ…์ŠคํŠธ ๋‚ด์—์„œ ์ƒํƒœ ์ €์žฅ ์‚ฌ๋ฌผ(AnimationController)์„ ์‰ฝ๊ฒŒ ํ•ฉ์„ฑํ•˜๋Š” ํ•ต์‹ฌ ๋ฌธ์ œ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋‘ ์ƒ์„ฑ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๋ณต์œผ๋กœ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. AnimatedBuilder + AnimatorController.use()๋กœ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— TAB์€ ๊ฑฐ์˜ ๋ฌด์˜๋ฏธํ•ด์ง‘๋‹ˆ๋‹ค.

์œ„์˜ ๋‚ด ์˜๊ฒฌ์„ ์ฝ์œผ๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ์Šคํ”„๋ง ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ›…์œผ๋กœ ์ˆ˜ํ–‰ํ•œ ์ž‘์—…๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋กœ์ง์„ ์บก์Šํ™”ํ•œ ๋‹ค์Œ ๋‹จ์ˆœํžˆ AnimatedBuilder๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์•”์‹œ์ ์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด AnimatedContainer์—์„œ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์†Œํ’ˆ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์ ์šฉ๋˜๋„๋ก didUpdateWidget ( didUpdateHook ์—์„œ flutter_hooks ) ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ „ ๊ฐ’์—์„œ ์ƒˆ ๊ฐ’์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

https://github.com/TimWhiting/local_widget_state_approaches/tree/master/lib/stateful ์˜ ์˜ˆ๊ฐ€ ์ด์ œ ์‚ฌ๋žŒ๋“ค์ด ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋Œ€ํ‘œํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๊นŒ?

์†”์งํžˆ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.
๋‚˜๋Š” _์˜ˆ_๋ผ๊ณ  ๋งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์ด๋Ÿฌํ•œ ์˜ˆ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด์„ํ•  ๊ฒƒ์ธ๊ฐ€์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ์—์„œ ์šฐ๋ฆฌ๋Š” ์„œ๋กœ๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์—ญ์‚ฌ๊ฐ€ ์žˆ์–ด์„œ ๋‹ค์‹œ๋Š” ์ด๋Ÿฐ ์ผ์ด ์ผ์–ด๋‚˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์žฅ๋‹ดํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋ถ€๋ถ„์ ์œผ๋กœ ๋‚ด๊ฐ€ ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์‹ซ์–ดํ•˜๊ณ  ๋Œ€์‹  ๊ทœ์น™ ์ง‘ํ•ฉ์„ ์ถ”์ถœํ•˜๋„๋ก ์ œ์•ˆํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.
์˜ˆ๋Š” ์ฃผ๊ด€์ ์ด๊ณ  ์—ฌ๋Ÿฌ ์†”๋ฃจ์…˜์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ๊ทธ ์ค‘ ์ผ๋ถ€๋Š” ๋” ๊ด‘๋ฒ”์œ„ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์ด ๋ฌธ์ œ์— ๋…ผ์˜๋œ ๋ชจ๋“  ์ฝ”๋“œ ์ƒ˜ํ”Œ์„ ํฌํ•จํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค .

local_state ์ €์žฅ์†Œ์— ์ถ”๊ฐ€ํ•˜๋Š” PR์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งค์šฐ ์œ ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด ์Šค๋ ˆ๋“œ๊ฐ€ ์žฌ์‚ฌ์šฉ์„ ์ •์˜ํ•˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์žฌ์‚ฌ์šฉ์ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€ ์ง€์ ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋Œ€ํ™”๊ฐ€ ์ดˆ์ ์„ ์žƒ์ง€ ์•Š๋„๋ก ์ •์˜ํ•  ๋•Œ ๊ณ ํ†ต์Šค๋Ÿฝ๊ฒŒ ๊ตฌ์ฒด์ ์ด์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

Flutter์™€ ๊ด€๋ จํ•˜์—ฌ ์žฌ์‚ฌ์šฉ์ด _์•„๋‹Œ_๋งŒ ํ‘œ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฝค ๋งŽ์€ ์‚ฌ์šฉ ์˜ˆ๊ฐ€ ์žˆ์—ˆ๊ณ  ํ›„ํฌ๋Š” ์œ„์ ฏ ์ƒํƒœ ์žฌ์‚ฌ์šฉ์˜ ์ „์ฒด ์˜ˆ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ฒ‰๋ณด๊ธฐ์— ์ง์„ค์ ์œผ๋กœ ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์— ํ˜ผ๋ž€์ด ์–ด๋””์—์„œ ๋น„๋กฏ๋œ ๊ฒƒ์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์žฌ์‚ฌ์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํžˆ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. _๋นŒ๋” ์œ„์ ฏ์ด ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ._

๋ชจ๋“  ์œ„์ ฏ ๋‚ด๋ถ€์— ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํƒœ ์ €์žฅ ๊ฐœ์ฒด์— ๋Œ€ํ•œ ์š”์ฒญ์ž…๋‹ˆ๋‹ค.

  • ์ž์‹ ์˜ ์ƒํƒœ๋ฅผ ์บก์Šํ™”
  • initState/dispose ํ˜ธ์ถœ์— ๋”ฐ๋ผ ์ž์ฒด์ ์œผ๋กœ ์„ค์ •/ํ•ด์ œ ๊ฐ€๋Šฅ
  • ์œ„์ ฏ์—์„œ ์ข…์†์„ฑ์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๋ฐ˜์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ์šฉ๊ตฌ ์—†์ด ์ค€๋น„ํ•˜๊ธฐ ์‰ฝ๊ณ  ๊ฐ„๊ฒฐํ•œ ๋ฐฉ์‹์œผ๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
AnimationController anim = AnimationController.stateful(duration: widget.duration);
์ด๊ฒƒ์ด Stateless ๋ฐ Stateful ์œ„์ ฏ์—์„œ ์ž‘๋™ํ•˜๋Š” ๊ฒฝ์šฐ. widget.something์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๋‹ค์‹œ ๋นŒ๋“œ๋˜๊ณ  ์ž์ฒด init() ๋ฐ dispose()๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ์Šน์ž๊ฐ€ ์žˆ๊ณ  ๋ชจ๋‘๊ฐ€ ๊ฐ์‚ฌํ•  ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๊ณ ๊ตฐ๋ถ„ํˆฌํ•˜๋Š” ์ฃผ์š” ๋ฌธ์ œ๋Š” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ValueListenableBuilder๋Š” ์„ฑ๋Šฅ์„ ์ธก์ • ๊ฐ€๋Šฅํ•˜๊ฒŒ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž์‹ ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Property ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. XTransition ์œ„์ ฏ์ด ์ง€๊ธˆ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ์ƒํƒœ๊ฐ€ ์žˆ๊ณ  ๊ฐ’๋น„์‹ผ ์ž์‹์„ ๊ฐ–๊ณ  ์‹ถ๋‹ค๋ฉด ์ž‘์€ ๋ž˜ํผ ์œ„์ ฏ์„ ๋งŒ๋“ค๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ:
FadeTransition(opacity: anim, child: someChild)

'์‚ฌ๋ฌผ'์„ ์œ„์ ฏ์— ์ „๋‹ฌํ•˜์—ฌ ๋‹ค์‹œ ๋ Œ๋”๋งํ•จ์œผ๋กœ์จ ๋ Œ๋”๋งํ•˜๋ ค๋Š” ๋ชจ๋“  ๊ฒƒ์œผ๋กœ ์‰ฝ๊ฒŒ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
MyThingRenderer(value: thing, child: someChild)

  • ์ด๊ฒƒ์€ ๋นŒ๋”์ฒ˜๋Ÿผ ์ค‘์ฒฉ์„ _ํ•„์š”๋กœ ํ•˜์ง€ ์•Š์ง€๋งŒ ์„ ํƒ์ ์œผ๋กœ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค(.child๋Š” ๋นŒ๋“œ fxn์ผ ์ˆ˜ ์žˆ์Œ).
  • ๋ž˜ํ•‘ ์œ„์ ฏ ์—†์ด ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ์šฐ๋ฆฌ๋Š” ํ•ญ์ƒ ๋นŒ๋”๋ฅผ ๋งŒ๋“ค๊ณ  ๋นŒ๋” ๋‚ด์—์„œ ์ด ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋” ๊นจ๋—ํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋™์ผํ•œ ํ•ต์‹ฌ ๊ฐœ์ฒด๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ๊ตฌ์ถ•๋œ ์—ฌ๋Ÿฌ ์œ ํ˜•์˜ ๋นŒ๋”์— ๋Œ€ํ•œ ๋ฌธ์„ ์—ด๋ฉฐ, ์—ฌ๊ธฐ์ €๊ธฐ์— ๋ณต์‚ฌ ๋ถ™์—ฌ๋„ฃ์€ ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@esDotDev์— ๋™์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด์— ๋Œ€ํ•œ ๋Œ€์ฒด ์ œ๋ชฉ์€ "๋นŒ๋”๋ฅผ ์œ„ํ•œ ๊ตฌ๋ฌธ ์„คํƒ•"์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๊ณ ๊ตฐ๋ถ„ํˆฌํ•˜๋Š” ์ฃผ์š” ๋ฌธ์ œ๋Š” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ValueListenableBuilder๋Š” ์„ฑ๋Šฅ์„ ์ธก์ • ๊ฐ€๋Šฅํ•˜๊ฒŒ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž์‹ ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Property ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. XTransition ์œ„์ ฏ์ด ์ง€๊ธˆ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ์ƒํƒœ๊ฐ€ ์žˆ๊ณ  ๊ฐ’๋น„์‹ผ ์ž์‹์„ ๊ฐ–๊ณ  ์‹ถ๋‹ค๋ฉด ์ž‘์€ ๋ž˜ํผ ์œ„์ ฏ์„ ๋งŒ๋“ค๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ:

๊ทธ๋Ÿด ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
์ด ๊ธฐ๋Šฅ์˜ ์ด์  ์ค‘ ํ•˜๋‚˜๋Š” "๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์œ„์ ฏ ์ธ์Šคํ„ด์Šค๋ฅผ ์บ์‹œ"ํ•˜๋Š” ์ƒํƒœ ๋…ผ๋ฆฌ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด React์—์„œ useMemo ๋ฉ๋‹ˆ๋‹ค.

<insert whatever>
final myWidget = useMemo(() => MyWidget(pameter: value), [value]);

์ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด value ๋ณ€๊ฒฝ๋  ๋•Œ myWidget ๊ฐ€ _only_ ๋‹ค์‹œ ๋นŒ๋“œ๋ฉ๋‹ˆ๋‹ค. useMemo ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์œ„์ ฏ์ด ๋‹ค๋ฅธ ์ด์œ ๋กœ ๋‹ค์‹œ ๋นŒ๋“œ๋˜๋”๋ผ๋„.

์ด๋Š” ์œ„์ ฏ์˜ const ์ƒ์„ฑ์ž์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ ๋™์  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

Tim์˜ ์ €์žฅ์†Œ์— ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ์œ„์ ฏ ๋‚ด๋ถ€์— ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํƒœ ์ €์žฅ ๊ฐœ์ฒด์— ๋Œ€ํ•œ ์š”์ฒญ์ž…๋‹ˆ๋‹ค.

  • ์ž์‹ ์˜ ์ƒํƒœ๋ฅผ ์บก์Šํ™”
  • initState/dispose ํ˜ธ์ถœ์— ๋”ฐ๋ผ ์ž์ฒด์ ์œผ๋กœ ์„ค์ •/ํ•ด์ œ ๊ฐ€๋Šฅ
  • ์œ„์ ฏ์—์„œ ์ข…์†์„ฑ์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๋ฐ˜์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ StatefulWidget ์ด ์ž‘์—…์„ ๋” ์ž˜ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์•Œ๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ์†”๋ฃจ์…˜์—์„œ ์šฐ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ์ถ”๊ตฌํ•˜๋Š” ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•œ ์งˆ๋ฌธ์„ ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. flutter_hooks ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ์œผ๋กœ์„œ ๋‚˜๋Š” ๊ทธ๊ฒƒ๋“ค์ด StatefulWidget ๋ณด๋‹ค ์ž‘์—…ํ•˜๋Š” ๊ฒƒ์ด ๋” ์žฌ๋ฏธ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์ง€๋งŒ ์ด๋Š” ๋‹จ์ง€ ์žฅํ™ฉํ•จ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ›„ํฌ์˜ ๊ด€์ ์—์„œ ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ Widget ๋น„ํ•ด ํ›„ํฌ์—์„œ UI ์—…๋ฐ์ดํŠธ์— ๋Œ€ํ•œ ์ถ”๋ก ์ด ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค.

  • ์œ„์ ฏ์—์„œ ์ข…์†์„ฑ์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๋ฐ˜์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์ ฏ ๋‚ด์—์„œ ์ƒ์„ฑ/ํš๋“๋œ ์ข…์†์„ฑ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ํŠธ๋ฆฌ์˜ ์œ„์ ฏ ์•„๋ž˜์— ์žˆ๋Š” ์ข…์†์„ฑ์ž…๋‹ˆ๊นŒ?

Flutter์— ์žฅํ™ฉํ•จ/ํ˜ผ๋ž€์„ ์ผ์œผํ‚ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ถ€์ •ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ "์žฌ์‚ฌ์šฉ"์ด ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•œ ๋™์ผํ•œ ์ •์‹  ๋ชจ๋ธ์„ ์‹ค์ œ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ์—๊ฒŒ ์˜์กดํ•˜๋Š” ๊ฒƒ์„ ์ฃผ์ €ํ•ฉ๋‹ˆ๋‹ค. ์„ค๋ช…ํ•ด์ฃผ์…”์„œ ์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด ๋‹ค๋ฅธ ๋ชจ๋ธ์„ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ ๊ทธ๋“ค์€ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

SW๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ ๋งŽ์€ SW์—์„œ ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋…ผ๋ฆฌ๋ฅผ ์ถ”์ƒํ™”ํ•˜๋Š” ๋ฐ๋Š” ์ข‹์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ์„ค์ •/ํ•ด์ฒด๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ SW ์ž์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ ์ „์ฒด์—์„œ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์บก์Šํ™”๋œ ์ƒํƒœ ๊ณต์œ ์— ๋Œ€ํ•œ ์ผ๊ธ‰ ์ง€์›์ด ์—†์œผ๋ฉด ๊ฒฐ๊ตญ ๋นŒ๋”(์˜ˆ: TweenAnimationBuilder)๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ํŠน์ • ์œ„์ ฏ(์˜ˆ: AnimatedContainer ๋“ฑ)์„ ๋งŽ์ด ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ๋…ผ๋ฆฌ๋ฅผ ๋ฒˆ๋“ค๋กœ ๋ฌถ์–ด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ํ›จ์”ฌ ๋” ์šฐ์•„ํ•ด์ง‘๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‹น์‹ ์ด ์›ํ•˜๋Š” ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ๋“  ๋‚˜๋ฌด ์•ˆ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์ ฏ ์ข…์†์„ฑ ์ธก๋ฉด์—์„œ ๋งํ•˜์ž๋ฉด, widget.foo ๋ณ€๊ฒฝ๋˜๋ฉด stateful-thing์€ ํ•„์š”ํ•œ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ๊ธฐํšŒ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. stateful AnimationController์˜ ๊ฒฝ์šฐ ์ง€์† ์‹œ๊ฐ„์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๋ณ€๊ฒฝ๋˜๋ฉด ๋‚ด๋ถ€ AnimatorController ์ธ์Šคํ„ด์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๋ชจ๋“  ๊ตฌํ˜„์ž๊ฐ€ ์†์„ฑ ๋ณ€๊ฒฝ์„ ์ฒ˜๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

<insert whatever>
final myWidget = useMemo(() => MyWidget(pameter: value), [value]);

์ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด value ๋ณ€๊ฒฝ๋  ๋•Œ myWidget ๊ฐ€ _only_ ๋‹ค์‹œ ๋นŒ๋“œ๋ฉ๋‹ˆ๋‹ค. useMemo ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์œ„์ ฏ์ด ๋‹ค๋ฅธ ์ด์œ ๋กœ ๋‹ค์‹œ ๋นŒ๋“œ๋˜๋”๋ผ๋„.

์•„, Memoized๋Š” ์œ„์ ฏ ์ž์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  [value]๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œ ํŠธ๋ฆฌ๊ฑฐ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ๊น”๋”ํ•ฉ๋‹ˆ๋‹ค!

AnimatedOpacity์˜ ํ•ต์‹ฌ์€ ๋ถ€๋ชจ๋„ ์ž์‹๋„ ๋‹ค์‹œ ๋นŒ๋“œํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ AnimatedOpacity๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ฉด ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํŠธ๋ฆฌ๊ฑฐํ•œ ์ฒซ ๋ฒˆ์งธ ํ”„๋ ˆ์ž„ ์ดํ›„์—๋Š” ๋ฌธ์ž ๊ทธ๋Œ€๋กœ ์•„๋ฌด ๊ฒƒ๋„ ๋‹ค์‹œ ๋นŒ๋“œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œ ๋‹จ๊ณ„๋ฅผ ์™„์ „ํžˆ ๊ฑด๋„ˆ๋›ฐ๊ณ  ๋ Œ๋” ๊ฐœ์ฒด์—์„œ ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค(๋ Œ๋” ํŠธ๋ฆฌ์—์„œ๋Š” ๋‹ค์‹œ ๊ทธ๋ฆฌ๊ธฐ๋งŒ ํ•˜๊ณ  ๋ฆด๋ ˆ์ด์•„์›ƒ์€ ํ•˜์ง€ ์•Š์œผ๋ฉฐ ์‹ค์ œ๋กœ ๋ ˆ์ด์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ํŽ˜์ธํŠธ๋„ ๋งค์šฐ ์ตœ์†Œํ™”๋จ). ์„ฑ๋Šฅ๊ณผ ๋ฐฐํ„ฐ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์— ์ƒ๋‹นํ•œ ์ฐจ์ด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ์ œ์‹œํ•˜๋Š” ์†”๋ฃจ์…˜์ด ๋ฌด์—‡์ด๋“  ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ์— ๊ตฌ์ถ•ํ•˜๋ ค๋ฉด ๊ทธ๋Ÿฌํ•œ ์„ฑ๋Šฅ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ถˆํ–‰ํžˆ๋„ ๋‚˜๋Š” ์ด ๋ฌธ์ œ์˜ ์˜ˆ๋ฅผ ์ง€์—ญ ์ฃผ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ๋Œ€์กฐํ•  ์‹œ๊ฐ„์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ฐ€๊นŒ์šด ์‹œ์ผ ๋‚ด์— ๊ทธ๊ฒƒ์„ ์–ป์ง€ ๋ชปํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฏ€๋กœ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๊ทธ๊ฒƒ์„ ๋ฐ๋ฆฌ๋Ÿฌ ๊ฐ€๊ณ  ์‹ถ๋‹ค๋ฉด ๋‚˜๋Š” ๊ดœ์ฐฎ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋นŒ๋“œ/๋ Œ๋”๋ง ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์— ์ •์˜๋œ ํ›„ํฌ์˜ ์„ฑ๋Šฅ๊ณผ ๊ด€๋ จํ•˜์—ฌ(์ด ๋ฌธ์ œ์˜ ์•ž๋ถ€๋ถ„์—์„œ ๋ˆ„๊ตฐ๊ฐ€ ์–ธ๊ธ‰ํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค), ์ €๋Š” React ๋ฌธ์„œ๋ฅผ ์ฝ๊ณ  ์ด FAQ๊ฐ€ ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ํ›„ํฌ ๋ชจ๋“  ๋ Œ๋”๋ง์—์„œ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๋•Œ๋ฌธ์— ์†๋„๊ฐ€ ๋Š๋ฆฐ ๊ฒฝ์šฐ ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์š”๊ตฌํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๊ทธ๋“ค์€ ์ธํ•ด ๊ฐ™์€ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋Šฅ์„ memoize ์ˆ˜์žˆ๊ฒŒ๋˜๊ณ  ๊ทธ ์ค‘ ํ•˜๋‚˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์ด์œ ์— ๋” ๋งํ•  useMemo ๋˜๋Š” useCallback .

https://reactjs.org/docs/hooks-faq.html#are -hooks-slow-because-of-creating-functions-in-render

ํ›„ํฌ ๋ชจ๋“  ๋ Œ๋”๋ง์—์„œ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๋•Œ๋ฌธ์— ์†๋„๊ฐ€ ๋Š๋ฆฐ ๊ฒฝ์šฐ ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์š”๊ตฌํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๊ทธ๋“ค์€ ์ธํ•ด ๊ฐ™์€ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋Šฅ์„ memoize ์ˆ˜์žˆ๊ฒŒ๋˜๊ณ  ๊ทธ ์ค‘ ํ•˜๋‚˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์ด์œ ์— ๋” ๋งํ•  useMemo ๋˜๋Š” useCallback .

๊ฑฑ์ •์€ ํ์‡„๋ฅผ ๋งŒ๋“œ๋Š” ๋น„์šฉ์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์‹ค์ œ๋กœ ์ƒ๋Œ€์ ์œผ๋กœ ์ €๋ ดํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋Š˜๋‚  ์ตœ์ ์˜ ๊ฒฝ์šฐ Flutter๊ฐ€ ๋ณด์—ฌ์ฃผ๋Š” ์„ฑ๋Šฅ์˜ ํ•ต์‹ฌ์€ ์ฝ”๋“œ๋ฅผ ์ „ํ˜€ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ๊ณผ ์ „ํ˜€ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ฌธ์ž ๊ทธ๋Œ€๋กœ ํŠน์ • ์ฝ”๋“œ ๊ฒฝ๋กœ๋ฅผ ์ „ํ˜€ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋งŒ๋“œ๋Š” ๋ฐ ๋งŽ์€ ๋…ธ๋ ฅ์„ ๊ธฐ์šธ์˜€์Šต๋‹ˆ๋‹ค(์˜ˆ: AnimatedOpacity์— ๋Œ€ํ•ด ๋นŒ๋“œ ๋‹จ๊ณ„๋ฅผ ์™„์ „ํžˆ ๊ฑด๋„ˆ๋›ฐ๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํŠธ๋ฆฌ๋ฅผ ๊ฑท๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ณ  ๋Œ€์‹  ์˜ํ–ฅ์„ ๋ฐ›๋Š” ๋…ธ๋“œ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ๋ฐฉ์‹).

๋‚˜๋Š” ๋™์˜ํ•œ๋‹ค. ์ €๋Š” Flutter ๋‚ด๋ถ€๋‚˜ ํ›„ํฌ ๋‚ด๋ถ€์— ๋Œ€ํ•ด ์ž˜ ์•Œ์ง€ ๋ชปํ•˜์ง€๋งŒ ํ›„ํฌ๊ฐ€ ์‹คํ–‰๋˜์–ด์•ผ ํ•˜๋Š” ์‹œ์ ๊ณผ ์‹คํ–‰๋˜์ง€ ์•Š์•„์•ผ ํ•  ์‹œ์ ์„ ํŒŒ์•…ํ•ด์•ผ ํ•˜๊ณ (์•„์ง ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ) ์„ฑ๋Šฅ์ด ํ›„ํ‡ดํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋งž์Šต๋‹ˆ๋‹ค.

์˜ค๋Š˜๋‚  Flutter๊ฐ€ ์ตœ์ ์˜ ๊ฒฝ์šฐ์— ๋‚˜ํƒ€๋‚ด๋Š” ์„ฑ๋Šฅ์˜ ํ•ต์‹ฌ์€ ์ฝ”๋“œ๋ฅผ ์ „ํ˜€ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ๊ณผ ์ „ํ˜€ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค.

์•ž์„œ ๋ช‡ ๋ฒˆ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ํ›„ํฌ๋Š” ์ด๋ฅผ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.
Tim์˜ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ์žˆ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ์˜ˆ์ œ๊ฐ€ ๊ทธ ์ฆ๊ฑฐ์ž…๋‹ˆ๋‹ค. ํ›„ํฌ ๋ณ€ํ˜•์€ useMemo ๋•๋ถ„์— StatefulWidget ๋ณ€ํ˜•๋ณด๋‹ค ๋œ ์ž์ฃผ ๋‹ค์‹œ ๋นŒ๋“œ๋ฉ๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ์˜ ์–ด๋”˜๊ฐ€์—์„œ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์— ๋Œ€ํ•ด ๋…ผ์˜ ์ค‘์ด๋ฏ€๋กœ ์ œ์•ˆ์œผ๋กœ๋„ ๋ ˆ์ด๋ธ”์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜์‘๊ณผ ํ•จ๊ป˜ ํ”Œ๋Ÿฌํ„ฐ์— ํ†ตํ•ฉ๋œ ํ›„ํฌ๋ฅผ ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ฒ˜์Œ react๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ƒํƒœ๋ฅผ ํ”Œ๋Ÿฌํ„ฐ๋กœ ๋ด…๋‹ˆ๋‹ค. ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ๊ฒฐ์ฝ” ๋˜๋Œ์•„ ๊ฐ€์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฌ์šด IMO์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ๋Š” stateful ์œ„์ ฏ๊ณผ usestate์— ๋“œ๋กญํ•œ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ๊ฐœ์˜ ํด๋ž˜์Šค๋ฅผ ์„ ์–ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๊ฐœ๋ฐœ์ž๋“ค์ด ํ”Œ๋Ÿฌํ„ฐ ์ฝ”๋“œ๋ฅผ ๋ณผ ๋•Œ ์ข…์ข… ๊ฐ–์ง€ ๋ชปํ•˜๋Š” ๋ฐ˜์‘์„ ํ”Œ๋Ÿฌํ„ฐ์— ์–ด๋Š ์ •๋„ ์ต์ˆ™ํ•˜๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ flutter์™€ react๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•œ ๊ธธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜์ด ํ›„ํฌ๊ฐ€ ์—†๋Š” ๊ฒฝํ—˜๋ณด๋‹ค ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ €๋Š” flutter btw๋ฅผ ์‹ซ์–ดํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ œ๊ฐ€ ๊ฐ€์žฅ ์ข‹์•„ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ด์ง€๋งŒ ๊ฐ€๋…์„ฑ๊ณผ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ๋†’์ผ ์ˆ˜ ์žˆ๋Š” ์ •๋ง ์ข‹์€ ๊ธฐํšŒ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋ช…๋ช… ๊ทœ์น™์„ ๊ฐœ์„ ํ•˜๊ณ  ๋” ํ™”๋ คํ•˜๊ฒŒ ๋งŒ๋“ค ๊ธฐํšŒ๊ฐ€ ๋ถ„๋ช…ํžˆ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

UseMemoized ๋ฐ UseEffect ๊ฐ™์€ ๊ฒƒ์€ ์ƒ๋‹นํžˆ ์ƒ์†Œํ•˜๊ฒŒ ๋“ค๋ฆฌ๋ฉฐ ๋นŒ๋“œ fxn์—์„œ init() ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๋ฐฉ๋ฒ•์„ ์›ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค.

ํ˜„์žฌ ํ›„ํฌ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค(์ œ ์ƒ๊ฐ์—๋Š”?).

Widget build(){
   useEffect(
      (){
          // Do init stuff
         return (){  //Do dispose stuff };
      }, [ ] ) //<-- pass an empty list of rebuild triggers, so this can only fire once. Passing null here would let it fire every time.
   );
}

๋‚˜๋Š” ์ด ์ฝ”๋“œ์˜ ๊ฐ„๊ฒฐํ•จ์— ๊ฐ์‚ฌํ•˜์ง€๋งŒ ๊ฐ€๋…์„ฑ๊ณผ "์ž์ฒด ๋ฌธ์„œํ™” ์ฝ”๋“œ" ๊ด€์ ์—์„œ ๋ณด๋ฉด ํ™•์‹คํžˆ ์ด์ƒ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋งŽ์€ ์•”์‹œ์  ๋งˆ์ˆ ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” init/dispose ํ›„ํฌ์— ๋Œ€ํ•ด ๋ช…์‹œ์ ์ด๋ฉฐ Stateless ์œ„์ ฏ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ•์ œ๋กœ ๋นŒ๋“œ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

useMemoized ๋ฐ useEffect์™€ ๊ฐ™์€ ํ•ญ๋ชฉ์€ ๋” ๋ช…์‹œ์ ์œผ๋กœ hook ComputedValue() ๋ฐ hook SideEffect() ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Widget build(BuildContext context){
   List<int> volumes = hook ComputedValue(
        execute: ()=>_getVolumeFromAudioSamples(widget.bytes), 
        dependencies: [ widget.bytes ]);

   hook SideEffect(
       execute: ()=>_recordSongChangedAnalytics()
       dependencies: [ widget.songUrl ]);
   )

   return SongVisualizer(volumes: volumes);
}

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์ข‹์•„ํ•˜์ง€๋งŒ hook ํ‚ค์›Œ๋“œ์˜ ์‚ฌ์šฉ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ๋Š๋ผ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ๊ณ  ๊ทธ๊ฒƒ์ด ์™ธ๊ตญ ๊ฐœ๋…์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ƒˆ ํ‚ค์›Œ๋“œ๋ฅผ ์†Œ๊ฐœํ•˜๋Š” ๊ฒƒ์€ ์ œ ์ƒ๊ฐ์—๋Š” withSideEffect ๋˜๋Š” withComputedValue ์™€ ๊ฐ™์€ ์ตœ์ƒ์˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด ์•„๋‹Œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์–ธ์–ด ๋””์ž์ด๋„ˆ๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ๋‚ด ๋ง์€ ๊ฐ€์น˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” Flutter์˜ ํ›„ํฌ์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์ด ํšŒ์‚ฌ๊ฐ€ ReactNative์™€ Flutter ์‚ฌ์ด์—์„œ ๊ฒฐ์ •์„ ๋‚ด๋ฆด ๋•Œ ์‹ค์ œ๋กœ ๋Œ€์ƒ์ด ๋˜๋Š” React ๊ฐœ๋ฐœ์ž์˜ ํ•™์Šต ๊ณก์„ ์„ ์›ํ™œํ•˜๊ฒŒ ํ•˜๋Š” ๋ฐ ํฐ ๋„์›€์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@lemusthelroy๋ฅผ ๋˜์ƒˆ๊ธฐ๋ฉฐ Flutter๋Š” ๋‹จ์—ฐ์ฝ” ์ œ๊ฐ€ ๊ฐ€์žฅ ์ข‹์•„ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ด๋ฉฐ ๊ทธ ๋ฐฉํ–ฅ์„ ๋ณด๊ฒŒ ๋˜์–ด ๋งค์šฐ ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐœ๋…์€ ์•„์ง ์ƒ๋Œ€์ ์œผ๋กœ ํƒ์ƒ‰๋˜์ง€ ์•Š์€ ๋ฐฉํ–ฅ์œผ๋กœ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์„ฑ์žฅ์‹œํ‚ค๋Š” ๋ฐ ํฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์€ React์™€ ๊ฑฐ๋ฆฌ๋ฅผ ๋‘๋ ค๋Š” ๋ชฉ์ ์œผ๋กœ ์ด ์•„์ด๋””์–ด๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ถˆํ–‰ํ•˜์ง€๋งŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„ค ๊ทธ ๋™์ „์—๋Š” ์–‘๋ฉด์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™์•„์š”. ์ƒˆ๋กœ์šด ํ‚ค์›Œ๋“œ๋Š” ์ฃผ์š” ์ด๋ฒคํŠธ์ด๋ฏ€๋กœ ์ง€์‹ ์ „ํŒŒ๋Š” ๋งค์šฐ ์‹ ์†ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ์ธก๋ฉด์€ ํ™•์‹คํžˆ _๋ชจ๋‘์—๊ฒŒ ์ƒˆ๋กœ์šด ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ ์—†์ด๋„ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ๋ฉ‹์ง€๋‹ค! ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค ... ์ ์–ด๋„ ์šฐ์•„ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

์˜๊ฒฌ: ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์‚ฌ์‹ค์ƒ์˜ ํ•ด๊ฒฐ์ฑ…์œผ๋กœ ํ›„ํฌ๋ฅผ ๋ช…๋ช…ํ•˜๋ ค๋Š” ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฒฝํ–ฅ์€ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํŽธ๊ฒฌ์—์„œ ๋น„๋กฏ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋Š” ํŠนํžˆ ์ •์ ์œผ๋กœ ์œ ํ˜•์ด ์ง€์ •๋œ ์–ธ์–ด์—์„œ ๊ฐœ์ฒด๋ณด๋‹ค ๊ตฌ์„ฑํ•˜๊ธฐ๊ฐ€ ๋” ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ Widget์˜ ๋ฉ˜ํƒˆ ๋ชจ๋ธ์€ ์‚ฌ์‹ค์ƒ build ๋ฐฉ์‹์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์ธก๋ฉด์—์„œ ๋ฌธ์ œ๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉด ๋‚˜๋จธ์ง€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ž˜ ์ž‘๋™ํ•˜๋Š” ์†”๋ฃจ์…˜์„ ์„ค๊ณ„ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋” ๋†’๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์ธก๋ฉด์—์„œ hook ํ‚ค์›Œ๋“œ์˜ ๊ฒฝ์šฐ; ์ผ์ข…์˜ ํ…œํ”Œ๋ฆฟ(๋งคํฌ๋กœ)์—์„œ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ณ  ์ •์˜ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ์œผ๋ฉฐ hook ์ ‘๋‘์‚ฌ๋Š” ์‹ค์ œ๋กœ ๋‚ด์žฅ ํ•จ์ˆ˜์— ๋‚ด๋ถ€ ์ƒํƒœ(c-style static.xml)๊ฐ€ ์žˆ์Œ์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. )

Swift FunctionBuilders์— ์–ด๋–ค ์ข…๋ฅ˜์˜ ์„ ํ–‰ ๊ธฐ์ˆ ์ด ์—†๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๊ฟˆ๊พธ๋Š” ๋™์•ˆ ํ•„์š”ํ•œ ์ฝ”๋“œ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ถ”์ธกํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Hook SideEffect(void Function() execute, List<Object> dependencies) {
  // Whatever happens each build.
}

Widget build(BuildContext context){
   List<int> volumes = hook ComputedValue(
        execute: ()=>_getVolumeFromAudioSamples(widget.bytes), 
        dependencies: [ widget.bytes ]);

   SideEffect(
       execute: ()=>_recordSongChangedAnalytics()
       dependencies: [ widget.songUrl ]);
   )

   return SongVisualizer(volumes: volumes);
}

์—ฌ๊ธฐ์„œ Hook ๋Š” ํ›„ํฌ์— ์ต์ˆ™ํ•œ ๊ฐœ๋ฐœ์ž๊ฐ€ ํ›„ํฌ ๋ฒ•์น™์œผ๋กœ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ ํ›„ํฌ๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ์Œ์„ ์ •์ ์œผ๋กœ ๋ถ„์„ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ์œ ํ˜• ์‹œ์Šคํ…œ ์ˆ˜์ค€ ํ•ดํ‚น์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์ข…๋ฅ˜์˜ ๊ฒƒ์œผ๋กœ Hook-type์€ ํ•จ์ˆ˜์™€ ๋งค์šฐ ์œ ์‚ฌํ•˜์ง€๋งŒ ์ •์  ๋‚ด๋ถ€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ ์ƒํƒœ๋ฅผ ๊ฐ€์ง„ ๊ฒƒ์œผ๋กœ ๋ฌธ์„œํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์–ธ์–ด์  ๊ด€์ ์—์„œ ๋ณด๋ฉด ๋„ˆ๋ฌด ์ด์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ธ€์„ ์“ฐ๋ฉด์„œ ์•ฝ๊ฐ„ ์›€์ธ ๋Ÿฌ๋“ญ๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, Dart๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํƒœ์–ด๋‚œ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ธฐ์ดํ•จ์ด ์–ด๋””์—๋‚˜ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋ฐ”๋กœ ์ด๊ณณ์ด ์•„๋‹๊นŒ. ํŠนํžˆ ์ด ์ด์ƒํ•จ๋งŒ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

์˜๊ฒฌ: ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์‚ฌ์‹ค์ƒ์˜ ํ•ด๊ฒฐ์ฑ…์œผ๋กœ ํ›„ํฌ๋ฅผ ๋ช…๋ช…ํ•˜๋ ค๋Š” ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฒฝํ–ฅ์€ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํŽธ๊ฒฌ์—์„œ ๋น„๋กฏ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋Š” ํŠนํžˆ ์ •์ ์œผ๋กœ ์œ ํ˜•์ด ์ง€์ •๋œ ์–ธ์–ด์—์„œ ๊ฐœ์ฒด๋ณด๋‹ค ๊ตฌ์„ฑํ•˜๊ธฐ๊ฐ€ ๋” ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ ์œ„์ ฏ์˜ ๋ฉ˜ํƒˆ ๋ชจ๋ธ์€ ์‚ฌ์‹ค์ƒ ๋นŒ๋“œ ๋ฐฉ๋ฒ•์ผ ๋ฟ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฑธ๋กœ ๋ฌด์Šจ ๋ง์„ ํ•˜๊ณ  ์‹ถ์€์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. get_it_mixin๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ํ›„ํฌ ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

React hooks ์— ๋Œ€ํ•œ ํฅ๋ฏธ๋กœ์šด ๊ธฐ์‚ฌ

@nt4f04uNd ์„ฑ๋Šฅ, ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ์ด์œ , ๊ธฐ๋Šฅ ๋Œ€ ํด๋ž˜์Šค ์Šคํƒ€์ผ ์œ„์ ฏ, ํ›„ํฌ ์ด์™ธ์˜ ๊ฒƒ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ด์œ  ๋“ฑ ๋ชจ๋“  ์š”์ ์€ ์ด์ „์— ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ์š”์ ์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์ „์ฒด ๋Œ€ํ™”๋ฅผ ์ฝ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋‹ค์–‘ํ•œ ์š”์ ์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์ „์ฒด ๋Œ€ํ™”๋ฅผ ์ฝ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๊ทธ๋“ค์ด ์ „์ฒด ์Šค๋ ˆ๋“œ๋ฅผ ์ฝ์ง€ ์•Š์•˜๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•˜๋ฉด ๊ณตํ‰ํ•˜์ง€๋งŒ ์Šค๋ ˆ๋“œ์˜ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์„ ์ฝ๋Š” ๊ฒƒ์ด ์ƒํ™ฉ์„ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š”์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์œ„์ ฏ์„ ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์šฐ์„ ์ธ ์‚ฌ๋žŒ๋“ค๊ณผ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ผ์„ ํ•˜๊ฑฐ๋‚˜ ์œ„์ ฏ์„ ๋ชจ๋“ˆํ™”ํ•˜๋ ค๋Š” ๋˜ ๋‹ค๋ฅธ ๊ทธ๋ฃน์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค์ผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ด ๋ฌธ์ œ๋Š” ํ˜„์žฌ ์œ„์ ฏ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Œ์„ ๋ณด์—ฌ์ฃผ๋ฏ€๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์ƒˆ๋กœ์šด ๊ฒƒ์„ ๋งŒ๋“ค ์ˆ˜ ๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Future ๊ฐ€ ์žˆ๊ณ  ๋‚˜์ค‘์— async/await ๊ตฌ๋ฌธ์„ ๋„์ž…ํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ํ›„์ž๋Š” ์ƒˆ๋กœ์šด ๊ตฌ๋ฌธ ์—†์ด๋Š” ๋ถˆ๊ฐ€๋Šฅํ–ˆ๋˜ ์ผ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ๋žŒ๋“ค์€ ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๊ฒƒ์„ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€๋กœ ๋งŒ๋“ค ๊ฒƒ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. React๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์œ ์ผํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— Javascript์— ์ƒˆ ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(๋ฐ”๋ฒจ ๋ณ€ํ™˜์„ ํ†ตํ•ด ๊ฐ€๋Šฅ). ํ•˜์ง€๋งŒ Dart๋Š” Flutter(์ตœ์†Œํ•œ ์›๋ณธ ๋ฒ„์ „์ด ์•„๋‹Œ Dart 2)์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋„๋ก ํŠน๋ณ„ํžˆ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๊ฐ€ ๊ธฐ๋ณธ ์–ธ์–ด์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋Š” ํ›จ์”ฌ ๋” ๋งŽ์€ ๊ธฐ๋Šฅ. ์˜ˆ๋ฅผ ๋“ค์–ด React๋Š” JSX์šฉ Babel์ด ํ•„์š”ํ•˜๊ณ  useEffect ์˜ค๋ฅ˜์— ๋Œ€ํ•ด ๋ฆฐํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜์ง€๋งŒ ์ปดํŒŒ์ผ ์‹œ๊ฐ„ ์˜ค๋ฅ˜๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŒจํ‚ค์ง€๊ฐ€ ์žˆ์œผ๋ฉด ์ฑ„ํƒ์ด ํ›จ์”ฌ ๋” ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. React hooks๊ฐ€ ํƒ€์‚ฌ ํŒจํ‚ค์ง€์˜€๋‹ค๋ฉด ์–ป์„ ์ˆ˜ ์—†์—ˆ๋˜ ๊ฒฌ์ธ๋ ฅ์„ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ Stateless ๋ฐ Stateful ์œ„์ ฏ ์™ธ์— HookWidget๊ณผ ๊ฐ™์€ ์„ธ ๋ฒˆ์งธ ์œ ํ˜•์˜ ์œ„์ ฏ์ด ์žˆ์œผ๋ฉด ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋Š ๊ฒƒ์„ ์‚ฌ์šฉํ• ์ง€ ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ๊ฒฐ์ •ํ•˜๊ฒŒ ํ•˜์‹ญ์‹œ์˜ค. ์ด๋ฏธ ๋ ˆ๋ฏธ์—์„œ ํŒจํ‚ค์ง€๊ฐ€ ์žˆ๊ธด ํ•˜์ง€๋งŒ ์–ด์ฉ” ์ˆ˜ ์—†์ด ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์‹œ๋„ํ–ˆ๊ณ  ๊ทธ๊ฒƒ์€ ์ƒ์šฉ๊ตฌ๋ฅผ ํฌ๊ฒŒ ์ค„์˜€์ง€๋งŒ ์ œํ•œ ๋•Œ๋ฌธ์— ๋ถˆํ–‰ํžˆ๋„ ๊ทธ๊ฒƒ์„ ๋–จ์–ด ๋œจ๋ ค์•ผํ–ˆ์Šต๋‹ˆ๋‹ค. init ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋งŒ ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ธ์–ด ์ง€์›์ด ํฌํ•จ๋œ ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€์ธ ๊ฒฝ์šฐ ์ถ”๊ฐ€๋กœ ํฐ ์ด์ ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ HookWidget์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๋” ์ตœ์ ํ™”๋˜๊ณ  ์„ฑ๋Šฅ์ด ๋›ฐ์–ด๋‚œ ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

init ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋งŒ ์ƒํƒœ ์ €์žฅ ์œ„์ ฏ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ ์ด๊ฒƒ์„ ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. useEffect()๋Š” ๋นŒ๋“œ ๋‚ด๋ถ€์—์„œ initCall์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์„œ๋Š” ์ด๊ฒƒ์„ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์ „ํ˜€ ๋…ธ๋ ฅํ•˜์ง€ ์•Š์œผ๋ฉฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹น์‹ ์ด ํ›„ํฌ์˜ ์ž‘๋™ ๋ฐฉ์‹์„ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋Š” React ๊ฐœ๋ฐœ์ž๋ผ๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ์ง€๋งŒ ํŒจํ‚ค์ง€์˜ ์ œํ•œ์œผ๋กœ ์ธํ•ด ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๊ณ  ์ •ํ™•ํžˆ ๋ฌด์—‡์ด์—ˆ๋Š”์ง€ ๊ธฐ์–ต๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰