Skip to content

Latest commit

ย 

History

History
731 lines (528 loc) ยท 27.2 KB

README.md

File metadata and controls

731 lines (528 loc) ยท 27.2 KB

English | French | Portuguรชs | ็ฎ€ไฝ“ไธญๆ–‡ | Espaรฑol | ํ•œ๊ตญ์–ด | เฆฌเฆพเฆ‚เฆฒเฆพ | ๆ—ฅๆœฌ่ชž | Turkish | Italian

Build Status codecov Discord

InheritedWidget์„ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ๋ณด๋‹ค ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด์ง„ ๋ž˜ํผ์ž…๋‹ˆ๋‹ค.

InheritedWidget์„ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ ๋Œ€์‹  provider๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ, ์•„๋ž˜์™€ ๊ฐ™์€ ์ด์ ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฆฌ์†Œ์Šค์˜ ๋‹จ์ˆœํ™”๋œ ํ• ๋‹น/ํ•ด์ œ
  • ์ง€์—ฐ ๋กœ๋”ฉ(lazy-loading)
  • ํด๋ž˜์Šค๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค ๋•Œ ๋งˆ๋‹ค ๋งค๋ฒˆ ์ž‘์„ฑํ•ด์•ผํ–ˆ๋˜ ๋ถ€๋ถ„์„ ํฌ๊ฒŒ ์ค„์ž„
  • devtool ์นœํ™”์  : Provider๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Application State๊ฐ€ Flutter devtool์— ํ‘œ์‹œ๋จ
  • ์ด๋Ÿฌํ•œ InheritedWidget๋“ค์„ ์†Œ๋น„(consume)ํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์„ ์ œ์‹œ (Provider.of/Consumer/Selector ์ฐธ๊ณ )
  • ๋ณต์žก์„ฑ์ด ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ์ฆ๊ฐ€ํ•˜๋Š” ์ˆ˜์‹  ๋งค์ปค๋‹ˆ์ฆ˜(listening mechanism)์„ ๊ฐ€์ง„ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ํ™•์žฅ์„ฑ ํ–ฅ์ƒ(์˜ˆ : ์•Œ๋ฆผ ๋ฐœ์†ก์— O(N)์ธ ChangeNotifier).

provider์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

์ฐธ๊ณ  ํ•ญ๋ชฉ:

4.x.x์—์„œ 5.0.0-nullsafety๋กœ์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

  • ์ด์ œ FutureProvider์™€ StreamProvider๋ฅผ ์œ„ํ•œ initialData๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

    ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์œ„ํ•ด ์•„๋ž˜์™€ ๊ฐ™์€ ๋‚ด์šฉ์€

    FutureProvider<int>(
      create: (context) => Future.value(42),
      child: MyApp(),
    )
    
    Widget build(BuildContext context) {
      final value = context.watch<int>();
      return Text('$value');
    }

    ์ด์ œ ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

    FutureProvider<int?>(
      initialValue: null,
      create: (context) => Future.value(42),
      child: MyApp(),
    )
    
    Widget build(BuildContext context) {
      // be sure to specify the ? in watch<int?>
      final value = context.watch<int?>();
      return Text('$value');
    }
  • ValueListenableProvider๊ฐ€ ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

    ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹œ, ๋Œ€์‹  Provider๋ฅผ ValueListenableBuilder์™€ ๊ฒฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ValueListenableBuilder<int>(
      valueListenable: myValueListenable,
      builder: (context, value, _) {
        return Provider<int>.value(
          value: value,
          child: MyApp(),
        );
      }
    )

์‚ฌ์šฉ๋ฒ•

๊ฐ’ ๋…ธ์ถœํ•˜๊ธฐ

์ƒˆ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ๋…ธ์ถœํ•˜๊ธฐ

Providers๋Š” ๋‹จ์ˆœํžˆ ๊ฐ’์„ ๋…ธ์ถœ ์‹œ์ผœ์ค„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๊ฐ’์˜ ์ƒ์„ฑ(create), ์ˆ˜์‹ (listen) ๊ทธ๋ฆฌ๊ณ  ํ•ด์ œ(dispose)๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

์‹ ๊ทœ ์ƒ์„ฑํ•œ ๊ฐ์ฒด๋ฅผ ๋…ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด provider์˜ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋งŒ์•ฝ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด .value ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งˆ์„ธ์š”. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์˜๋„์น˜ ์•Š์€ ๋ถ€์ž‘์šฉ์ด ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ’์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด .value ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์™œ ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š์€์ง€ ํ™•์ธํ•˜๋ ค๋ฉด StackOverflow ๋‹ต๋ณ€์„ ํ™•์ธํ•˜์„ธ์š”.

  • DO : create ์•ˆ์—์„œ ์‹ ๊ทœ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”.
Provider(
  create: (_) => MyModel(),
  child: ...
)
  • DON'T : ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด Provider.value๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”.
ChangeNotifierProvider.value(
  value: MyModel(),
  child: ...
)
  • DON'T : ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜๋กœ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ๋งˆ์„ธ์š”.

    ๋งŒ์•ฝ ๊ทธ๋ ‡๊ฒŒ ์ƒ์„ฑํ•˜์˜€๋‹ค๋ฉด, ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋Š” ๊ฐ’์ด ๋ณ€ํ™”ํ•ด๋„ ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

int count;

Provider(
  create: (_) => MyModel(count),
  child: ...
)

๋งŒ์•ฝ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜๋ฅผ ๊ฐ์ฒด์— ์ „๋‹ฌํ•˜๋ ค๋ฉด ProxyProvider ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

int count;

ProxyProvider0(
  update: (_, __) => MyModel(count),
  child: ...
)

NOTE:

provider์˜ create/update ์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•  ๋•Œ, ์ด ์ฝœ๋ฐฑ์ด ๊ธฐ๋ณธ์ ์œผ๋กœ Lazyํ•˜๊ฒŒ ํ˜ธ์ถœ๋œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ํ•ด๋‹น ๊ฐ’์„ ํ•œ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์—๋Š” create/update ์ฝœ๋ฐฑ์ด ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ๋™์ž‘์€ lazy ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ์ผ๋ถ€ ๋กœ์ง์„ ์‚ฌ์ „ ์—ฐ์‚ฐ(pre-compute)ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ์šฐ ๋น„ํ™œ์„ฑํ™” ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MyProvider(
  create: (_) => Something(),
  lazy: false,
)

๊ธฐ์กด ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ

๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ด๋ฏธ ์ƒ์„ฑ๋˜์—ˆ๊ณ , ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๋…ธ์ถœ์‹œํ‚ค๊ธธ ์›ํ•˜๋Š” ๊ฒฝ์šฐ provider์˜ .value ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค.

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

  • DO : ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ChangeNotifier๋ฅผ ๊ณต๊ธ‰(provide)ํ•˜๊ธฐ ์œ„ํ•ด์„œ ChangeNotifierProvider.value๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
MyChangeNotifier variable;

ChangeNotifierProvider.value(
  value: variable,
  child: ...
)
  • DON'T : ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ChangeNotifier๋ฅผ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์žฌ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”.
MyChangeNotifier variable;

ChangeNotifierProvider(
  create: (_) => variable,
  child: ...
)

๊ฐ’ ์ฝ๊ธฐ

๊ฐ’์„ ์ฝ๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ BuildContext์˜ ํ™•์žฅ ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • context.watch<T>() : ์œ„์ ฏ์ด T์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • context.read<T>() : T๋ฅผ ๋ณ€ํ™” ๊ฐ์ง€ ์—†์ด return ํ•ฉ๋‹ˆ๋‹ค.
  • context.select<T, R>(R cb(T value)) : T์˜ ์ผ๋ถ€ ์ž‘์€ ์˜์—ญ์— ๋Œ€ํ•ด์„œ๋งŒ ์œ„์ ฏ์ด ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ watch์™€ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š” ์ •์  ๋ฉ”์†Œ๋“œ(static method)์ธ Provider.of<T>(context)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. Provider.of<T>(context, listen: false)์ฒ˜๋Ÿผ listen ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ false๋กœ ํ•˜๋ฉด read์™€ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

context.read<T>()๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ์œ„์ ฏ์„ ์žฌ๋นŒ๋“œํ•˜์ง€ ์•Š์Œ์œผ๋กœ StatelessWidget.build/State.build ์•ˆ์—์„œ ํ˜ธ์ถœ๋  ์ˆ˜ ์—†์Œ์„ ์œ ์˜ํ•˜์„ธ์š”. ๋ฐ˜๋ฉด, ์ด๋Ÿฌํ•œ ๋ฉ”์†Œ๋“œ๋“ค ๋ฐ–์—์„œ๋Š” ์ž์œ ๋กญ๊ฒŒ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฉ”์†Œ๋“œ๋“ค์€ ์ „๋‹ฌ๋œ BuildContext์™€ ๊ด€๋ จ๋œ ์œ„์ ฏ์—์„œ ์‹œ์ž‘ํ•ด ์œ„์ ฏ ํŠธ๋ฆฌ์—์„œ ๋ฐœ๊ฒฌ๋˜๋ฉฐ, ๋ฐœ๊ฒฌ๋œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด T ํƒ€์ž… ๋ณ€์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. (์•„๋ฌด๊ฒƒ๋„ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒ ํ•ฉ๋‹ˆ๋‹ค.)

์ด ์ž‘์—…์€ O(1)์ž…๋‹ˆ๋‹ค. ์ž‘์—…์— ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ํƒ์ƒ‰ํ•˜๋Š” ์ผ์ด ํฌํ•จ ๋˜์–ด์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ์œ„์ ฏ์€ ์ฒซ ๋ฒˆ์งธ ์˜ˆ์‹œ์ธ ๊ฐ’ ๋…ธ์ถœํ•˜๊ธฐ์—์„œ ๋…ธ์ถœ๋œ String์„ ์ฝ๊ณ  "Hello World."๋ฅผ ๋ Œ๋”ํ•ฉ๋‹ˆ๋‹ค.

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
      // Don't forget to pass the type of the object you want to obtain to `watch`!
      context.watch<String>(),
    );
  }
}

์ด๋Ÿฌํ•œ ๋ฉ”์†Œ๋“œ๋“ค์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹ ์—, ์šฐ๋ฆฌ๋Š” Consumer์™€ Selector๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์€ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ฑฐ๋‚˜, provider์˜ BuildContext ํ•˜์œ„ ํ•ญ๋ชฉ์— ์ ‘๊ทผํ•˜๊ธฐ ์–ด๋ ค์šธ ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋” ๋งŽ์€ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

provider์˜ ์„ ํƒ์  ์˜์กด

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

๊ทธ๋ ‡๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ, context.watch/context.read์„ ํ˜ธ์ถœํ•  ๋•Œ generic ํƒ€์ž… ๋Œ€์‹  nullable ํƒ€์ž…์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ,

context.watch<Model>()

๋งค์นญ๋˜๋Š” provider๋ฅผ ์ฐพ์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ ProviderNotFoundException ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด,

context.watch<Model?>()

๋งค์นญ๋˜๋Š” provider๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๋”๋ผ๋„ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๋Œ€์‹ , null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

MultiProvider

๊ทœ๋ชจ๊ฐ€ ํฐ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋งŽ์€ ๊ฐ’์„ ์ฃผ์ž…ํ•˜๋ฉด Provider๊ฐ€ ๊ธ‰๊ฒฉํ•˜๊ฒŒ ์ค‘์ฒฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Provider<Something>(
  create: (_) => Something(),
  child: Provider<SomethingElse>(
    create: (_) => SomethingElse(),
    child: Provider<AnotherThing>(
      create: (_) => AnotherThing(),
      child: someWidget,
    ),
  ),
),

์ด๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MultiProvider(
  providers: [
    Provider<Something>(create: (_) => Something()),
    Provider<SomethingElse>(create: (_) => SomethingElse()),
    Provider<AnotherThing>(create: (_) => AnotherThing()),
  ],
  child: someWidget,
)

๋‘ ์ฝ”๋“œ๋Š” ์™„์ „ํžˆ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. MultiProvider๋Š” ์˜ค์ง ์ฝ”๋“œ์˜ ์™ธ๊ด€์„ ๋ฐ”๊ฟ”์ค„ ๋ฟ์ž…๋‹ˆ๋‹ค.

ProxyProvider

3.0.0 ๋ฒ„์ ผ๋ถ€ํ„ฐ ์ƒˆ๋กœ์šด provider์ธ ProxyProvider๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ProxyProvider๋Š” ๋‹ค๋ฅธ provider๋“ค์˜ ์—ฌ๋Ÿฌ ๊ฐ’์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ฌถ์–ด Provider๋กœ ์ „๋‹ฌํ•˜๋Š” provider์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ํ•ด๋‹น ์‹ ๊ทœ ๊ฐ์ฒด๋Š” ์šฐ๋ฆฌ๊ฐ€ ์˜์กดํ•˜๋Š” provider ์ค‘ ํ•˜๋‚˜๊ฐ€ ์—…๋ฐ์ดํŠธ๋  ๋•Œ๋งˆ๋‹ค ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค.

์•„๋ž˜ ์˜ˆ์ œ์—์„œ๋Š” ๋‹ค๋ฅธ provider์—์„œ ์˜จ counter๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ translations๋ฅผ ๋นŒ๋“œํ•˜๊ธฐ ์œ„ํ•ด ProxyProvider ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Widget build(BuildContext context) {
  return MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (_) => Counter()),
      ProxyProvider<Counter, Translations>(
        update: (_, counter, __) => Translations(counter.value),
      ),
    ],
    child: Foo(),
  );
}

class Translations {
  const Translations(this._value);

  final int _value;

  String get title => 'You clicked $_value times';
}

์ด๊ฒƒ์€ ์•„๋ž˜์™€ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋ณ€ํ˜•์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

  • ProxyProvider vs ProxyProvider2 vs ProxyProvider3, ...

    ํด๋ž˜์Šค ์ด๋ฆ„ ๋’ค์˜ ์ˆซ์ž๋Š” ProxyProvider๊ฐ€ ์˜์กดํ•˜๋Š” ๋‹ค๋ฅธ ๊ณต๊ธ‰์ž์˜ ์ˆ˜์ž…๋‹ˆ๋‹ค.

  • ProxyProvider vs ChangeNotifierProxyProvider vs ListenableProxyProvider, ...

    ๋ชจ๋‘ ๋น„์Šทํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€๋งŒ, ChangeNotifierProxyProvider๋Š” ๊ฐ’์„ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ Provider๋ฅผ ๋ณด๋‚ด๋Š” ๋Œ€์‹ , ChangeNotifierProvider๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

FAQ

๋‚ด ๊ฐ์ฒด๋“ค์„ ์ธ์ŠคํŽ™ํ„ฐ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‚˜์š”?

Flutter๋Š” ์ง€์ •๋œ ์‹œ์ ์— ์œ„์ ฏ ํŠธ๋ฆฌ๊ฐ€ ์–ด๋–ค ๊ฒƒ์ธ์ง€ ๋ณด์—ฌ์ฃผ๋Š” devtool์ด ํ•จ๊ป˜ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

provider๋Š” ์œ„์ ฏ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ devtool์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ํ•œ provider๋ฅผ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น provider๊ฐ€ ๋…ธ์ถœํ•˜๊ณ  ์žˆ๋Š” ๊ฐ’์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(example ํด๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” devtool ์Šคํฌ๋ฆฐ์ƒท)

devtool์— "Instance of MyClass" ๋ฐ–์— ์•ˆ๋ณด์—ฌ์š”. ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜๋‚˜์š”?

๊ธฐ๋ณธ์ ์œผ๋กœ devTool์€ toString์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ ์„ค์ •์ธ "Instance of MyClass"๋กœ ๋ณด์—ฌ์ง‘๋‹ˆ๋‹ค.

๋ณด๋‹ค ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‘ ๊ฐ€์ง€ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • Flutter์˜ Diagnosticable API๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

    ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๊ฐ์ฒด์— debugFillProperties๋กœ ์ปค์Šคํ…€ํ•œ DiagnosticableTreeMixin๋ฅผ ์‚ฌ์šฉ

    class MyClass with DiagnosticableTreeMixin {
      MyClass({this.a, this.b});
    
      final int a;
      final String b;
    
      @override
      void debugFillProperties(DiagnosticPropertiesBuilder properties) {
        super.debugFillProperties(properties);
        // list all the properties of your class here.
        // See the documentation of debugFillProperties for more information.
        properties.add(IntProperty('a', a));
        properties.add(StringProperty('b', b));
      }
    }
  • toString์„ ์žฌ์ •์˜(override) ํ•˜์„ธ์š”.

    ๋งŒ์•ฝ DiagnosticableTreeMixin๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋ฉด (Flutter๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํŒจํ‚ค์ง€ ๋“ฑ), toString๋ฅผ ์žฌ์ •์˜ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

    class MyClass with DiagnosticableTreeMixin {
      MyClass({this.a, this.b});
    
      final int a;
      final String b;
    
      @override
      String toString() {
        return '$runtimeType(a: $a, b: $b)';
      }
    }

Provider๋ฅผ initState์•ˆ์— ๋„ฃ์—ˆ์„ ๋•Œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜๋‚˜์š”?

์ด ์˜ˆ์™ธ๋Š” ๋‹ค์‹œ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š” ์ƒ๋ช… ์ฃผ๊ธฐ(life-cycle)์—์„œ provider๋ฅผ ๊ฐ์ง€ํ•˜๋ ค๊ณ  ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋•Œ๋ฌธ์— build์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ์ƒ๋ช… ์ฃผ๊ธฐ์—์„œ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ์—…๋ฐ์ดํŠธ์— ๊ด€๋ จ ์—†์Œ์„ ๋ช…์‹œํ•ด์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹ ,

initState() {
  super.initState();
  print(context.watch<Foo>().value);
}

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Value value;

Widget build(BuildContext context) {
  final value = context.watch<Foo>().value;
  if (value != this.value) {
    this.value = value;
    print(value);
  }
}

์ด๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ) 'value๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

๋˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

initState() {
  super.initState();
  print(context.read<Foo>().value);
}

์ด๋Š” value๋ฅผ ํ•œ๋ฒˆ ์ถœ๋ ฅํ•˜๊ณ  ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์ฒด๋“ค์˜ hot-reload๋ฅผ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‚˜์š”?

์ œ๊ณต๋œ ๊ฐ์ฒด์— ReassembleHandler๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Example extends ChangeNotifier implements ReassembleHandler {
  @override
  void reassemble() {
    print('Did hot-reload');
  }
}

๊ทธ ํ›„ ์ผ๋ฐ˜์ ์œผ๋กœ provider์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ChangeNotifierProvider(create: (_) => Example()),

ChangeNotifier๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์—…๋ฐ์ดํŠธํ•  ๋•Œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š” ๊ฑฐ์ฃ ?

์œ„์ ฏ ํŠธ๋ฆฌ๊ฐ€ ๋นŒ๋“œ๋˜๋Š” ๋™์•ˆ ํ•˜์œ„ ํ•ญ๋ชฉ ์ค‘ ํ•˜๋‚˜์—์„œ ChangeNotifier๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์€ notifier ์•ˆ์— future๊ฐ€ ์ €์žฅ๋œ ์ƒํƒœ์—์„œ http ์š”์ฒญ์„ ์‹œ์ž‘ํ•  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

initState() {
  super.initState();
  context.read<MyNotifier>().fetchSomething();
}

์ƒํƒœ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋™๊ธฐํ™”๋˜์–ด์žˆ์œผ๋ฏ€๋กœ ์ด ์ž‘์—…์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๋Š” ์ฆ‰, ์–ด๋–ค ์œ„์ ฏ์€ ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚˜๊ธฐ ์ „์— ๋นŒ๋“œ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ(์˜ค๋ž˜๋œ ๊ฐ’์„ ๋ฐ›์Œ), ๋˜ ์–ด๋–ค ์œ„์ ฏ์€ ๋ณ€๊ฒฝ์ด ์™„๋ฃŒ๋œ ํ›„์— ๋นŒ๋“œ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์ƒˆ๋กœ์šด ๊ฐ’์„ ๋ฐ›์Œ). ์ด๋กœ์ธํ•ด UI์— ๋ถˆ์ผ์น˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ด๋Š” ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋Œ€์‹  ์ „์ฒด ํŠธ๋ฆฌ์— ๋™์ผํ•˜๊ฒŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ์œ„์น˜์—์„œ ๋ณ€๊ฒฝ์„ ์ˆ˜ํ–‰ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

  • ๋ชจ๋ธ์˜ provider ์ƒ์„ฑ์ž create์ธ์ž ์•ˆ์—์„œ ์ง์ ‘ ์ˆ˜ํ–‰ํ•˜๊ธฐ :

    class MyNotifier with ChangeNotifier {
      MyNotifier() {
        _fetchSomething();
      }
    
      Future<void> _fetchSomething() async {}
    }

    ์™ธ๋ถ€ ๋ณ€์ˆ˜๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ํ”„๋ ˆ์ž„ ๋์— ๋น„๋™๊ธฐ์‹์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๊ธฐ :

    initState() {
      super.initState();
      Future.microtask(() =>
        context.read<MyNotifier>().fetchSomething(someValue);
      );
    }

    ์•ฝ๊ฐ„ ๋œ ์ด์ƒ์ ์ด์ง€๋งŒ, ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ณต์žกํ•œ ์ƒํƒœ์˜ ๊ฒฝ์šฐ ChangeNotifier๋ฅผ ์จ์•ผํ•˜๋‚˜์š”?

์•„๋‹™๋‹ˆ๋‹ค.

๋ชจ๋“  ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋Œ€์ฒด ๊ตฌ์กฐ๋กœ Provider.value()์™€ StatefulWidget๋ฅผ ๊ฒฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ์˜ˆ์‹œ๋Š” ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐ˜์ฆ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค.

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

  final Widget child;

  @override
  ExampleState createState() => ExampleState();
}

class ExampleState extends State<Example> {
  int _count;

  void increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Provider.value(
      value: _count,
      child: Provider.value(
        value: this,
        child: widget.child,
      ),
    );
  }
}

๋‹ค์Œ ์ž‘์—…์„ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

return Text(context.watch<int>().toString());

๋˜ํ•œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

return FloatingActionButton(
  onPressed: () => context.read<ExampleState>().increment(),
  child: Icon(Icons.plus_one),
);

๋˜๋Š” ์ง์ ‘ provider๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋งŒ์˜ provider๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‚˜์š”?

๋„ค. provider๋Š” provider๋ฅผ ์™„์ „ํ•˜๊ฒŒ ๊ตฌ์„ฑํ•˜๋Š” ์ž‘์€ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๋ชจ๋‘ ๊ณต๊ฐœํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒƒ๋“ค์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

  • ์–ด๋–ค ์œ„์ ฏ์ด๋˜์ง€ MultiProvider์™€ ํ•จ๊ป˜ ๋™์ž‘ํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ฃผ๋Š” SingleChildStatelessWidget. ์ด ์ธํ„ฐํŽ˜์ด์Šค๋Š” package:provider/single_child_widget์˜ ์ผ๋ถ€๋กœ ๋…ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

  • context.watch๋ฅผ ํ•  ๋•Œ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ผ๋ฐ˜์ ์ธ InheritedWidget์ธ InheritedProvider.

๋‹ค์Œ์€ ValueNotifier๋ฅผ ์ƒํƒœ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž ์ง€์ • provider์˜ ์˜ˆ์ž…๋‹ˆ๋‹ค. https://gist.github.com/rrousselGit/4910f3125e41600df3c2577e26967c91

์œ„์ ฏ์ด ๋„ˆ๋ฌด ์ž์ฃผ ์žฌ๋นŒ๋“œ๋ฉ๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ํ•˜๋‚˜์š”?

context.watch๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹ , ๊ฐ์ฒด์˜ ํŠน์ •ํ•œ ๋ถ€๋ถ„ ๋งŒ์„ ์ถ”์ ํ•˜๋Š” context.select๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•œ๋‹ค๋ฉด,

Widget build(BuildContext context) {
  final person = context.watch<Person>();
  return Text(person.name);
}

name์ด ์•„๋‹Œ ๋‹ค๋ฅธ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ ์œ„์ ฏ์ด ์žฌ๋นŒ๋“œ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋Œ€์‹ ์— context.select๋ฅผ ์‚ฌ์šฉํ•ด name ํ”„๋กœํผํ‹ฐ๋งŒ ์ถ”์ ํ•˜๊ฒŒํ•˜๋ฉด,

Widget build(BuildContext context) {
  final name = context.select((Person p) => p.name);
  return Text(name);
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด name ํ”„๋กœํผํ‹ฐ๊ฐ€ ์•„๋‹Œ ๋ณ€ํ™”๊ฐ€ ๋ฐœ์ƒํ•˜๋”๋ผ๋„ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์œ„์ ฏ์„ ์žฌ๋นŒ๋“œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์œ ์‚ฌํ•˜๊ฒŒ Consumer/Selector๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋“ค์ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” child ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์œ„์ ฏ ํŠธ๋ฆฌ์˜ ํŠน์ • ๋ถ€๋ถ„๋งŒ ์žฌ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.

Foo(
  child: Consumer<A>(
    builder: (_, a, child) {
      return Bar(a: a, child: child);
    },
    child: Baz(),
  ),
)

์œ„ ์˜ˆ์‹œ์—์„œ A๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜์—ˆ์„ ๋•Œ ์˜ค์ง Bar๋งŒ ์žฌ๋นŒ๋“œ๋ฉ๋‹ˆ๋‹ค. Foo๋Š” ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์žฌ๋นŒ๋“œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋™์ผํ•œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ provider๋“ค์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‚˜์š”?

์—†์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ provider๊ฐ€ ๋™์ผํ•œ ํƒ€์ž…์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์œ„์ ฏ์€ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์ƒ์œ„ provider ํ•˜๋‚˜ ๋งŒ์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€์‹  ๋‘ provider์—๊ฒŒ ๋ช…์‹œ์ ์œผ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์„ ์ œ๊ณตํ•˜๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹ ,

Provider<String>(
  create: (_) => 'England',
  child: Provider<String>(
    create: (_) => 'London',
    child: ...,
  ),
),

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Provider<Country>(
  create: (_) => Country('England'),
  child: Provider<City>(
    create: (_) => City('London'),
    child: ...,
  ),
),

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๊ตฌํ˜„์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‚˜์š”?

๋„ค, ์ƒ์„ฑ ์‹œ ์ œ๊ณต๋œ ๊ตฌํ˜„๊ณผ ํ•จ๊ป˜ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์‚ฌ์šฉ๋  ๊ฒƒ์ž„์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ˜•์‹ ํžŒํŠธ๋ฅผ ์ปดํŒŒ์ผ๋Ÿฌ์— ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

abstract class ProviderInterface with ChangeNotifier {
  ...
}

class ProviderImplementation with ChangeNotifier implements ProviderInterface {
  ...
}

class Foo extends StatelessWidget {
  @override
  build(context) {
    final provider = Provider.of<ProviderInterface>(context);
    return ...
  }
}

ChangeNotifierProvider<ProviderInterface>(
  create: (_) => ProviderImplementation(),
  child: Foo(),
),

ํ˜„์žฌ ์ œ๊ณต๋˜๋Š” provider

provider ๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด ํƒ€์ž…์— ๋Œ€ํ•ด ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ "provider"๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ๊ฐ์ฒด์˜ ๋ฆฌ์ŠคํŠธ๋Š” ์—ฌ๊ธฐ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฆ„ ์„ค๋ช…
Provider The most ๊ธฐ๋ณธ์ ์ธ provider ํ˜•ํƒœ. ์–ด๋–ค ๊ฐ’์ด๋“  ๊ฐ„์— ๊ฐ’์„ ๋…ธ์ถœ์‹œํ‚ต๋‹ˆ๋‹ค.
ListenableProvider Listenable ๊ฐ์ฒด๋ฅผ ์œ„ํ•œ ํŠน์ˆ˜ํ•œ provider. ListenableProvider๋Š” listener๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ์˜ค๋ธŒ์ ํŠธ์— ์ข…์†๋œ ์œ„์ ฏ์„ ์žฌ๊ตฌ์„ฑํ•˜๋„๋ก ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.
ChangeNotifierProvider ChangeNotifier์šฉ ListenableProvider ์‚ฌ์–‘. ํ•„์š”ํ•  ๋•Œ ์ž๋™์œผ๋กœ ChangeNotifier.dispose๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
ValueListenableProvider ValueListenable์„ ์ˆ˜์‹ ํ•˜๊ณ , ValueListenable.value๋งŒ์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
StreamProvider ์ŠคํŠธ๋ฆผ์„ ์ˆ˜์‹ ํ•˜๊ณ  ์ตœ์‹  ๊ฐ’์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
FutureProvider Future๋ฅผ ๋ฐ›๊ณ , ์™„์„ฑ๋˜์—ˆ์„ ๋•Œ ์˜์กด๋œ ๊ฐ์ฒด๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋„ˆ๋ฌด ๋งŽ์€ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด StackOverflowError ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜๋ฉด ์ข‹์„๊นŒ์š”?

๋งŒ์•ฝ ๋งค์šฐ ๋งŽ์€ ํ”„๋กœ๋ฐ”์ด๋”(150 ์ด์ƒ)๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ, ํ•œ ๋ฒˆ์— ๋งŽ์€ ์œ„์ ฏ์„ ๋นŒ๋“œ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋””๋ฐ”์ด์Šค์— ๋”ฐ๋ผ์„œ๋Š” StackOverflowError ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ ๋ช‡ ๊ฐ€์ง€ ํ•ด๊ฒฐ์ฑ…์ด ์žˆ์Šต๋‹ˆ๋‹ค.

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

    ์•„๋ž˜์˜ ์˜ˆ์ œ์ฝ”๋“œ์™€ ๊ฐ™์„ ๊ฒฝ์šฐ:

    MultiProvider(
      providers: [
        if (step1) ...[
          <lots of providers>,
        ],
        if (step2) ...[
          <some more providers>
        ]
      ],
    )

    ์Šคํ”Œ๋ž˜์‹œ ์Šคํฌ๋ฆฐ ์• ๋‹ˆ๋ฉ”์ด์…˜์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•ด๋ณด์„ธ์š”.

    bool step1 = false;
    bool step2 = false;
    @override
    initState() {
      super.initState();
      Future(() {
        setState(() => step1 = true);
        Future(() {
          setState(() => step2 = true);
        });
      });
    }
  • MultiProvider๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

    • MultiProvider ๋Š” ๊ฐ ํ”„๋กœ๋ฐ”์ด๋”์˜ ์‚ฌ์ด์— ์œ„์ ฏ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
    • MultiProvider ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” StackOverflowError ์— ์ด๋ฅผ ๋•Œ๊นŒ์ง€์˜ ์ œํ•œ์„ ๋Š˜๋ฆด ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Sponsors