MultiProvider, FutureProvider, StreamProvider

소밍·2023년 9월 6일
0
post-thumbnail

MultiProvider

가령 두개의 다른 타입의 ChangeNotifierProvider가 존재하고 한 위젯에서 이 모두에게 접근해야할 때 사용
만약 여러개의 Provider가 계층 구조를 이룬다면 가독성도 떨어지고 코드가 효율적으로 보이지 않음

Provider(
create: (context) => ModelA(),
child: Provider(
    create: (context) => ModelB(),
    child: Provider(
      create: (context) => ModelC(),
      child: MaterialApp(),
    ), 
  ),
);
MultiProvider(
  provider:[
    Provider(create: (context) => ModelA,
    Provider(create: (context) => ModelB,
    Provider(create: (context) => ModelC, 
  ],
  child: MaterialApp(),
);

FutureProvider

일반적으로 Future를 반환하는 함수를 사용하여 값을 제공하는 Provider

StreamProvider

주가 지수와 같이 연속되는 future value는 StreamBuilder로 값을 보여준다.
하지만 만약 Stream 값을 여러 위젯에서 access 하고자 한다면 StreamProvider를 사용하는 것이 좋다.

class Babies {
  final int age;

  Babies({required this.age});

   Future<int> getBabies() async {
    await Future.delayed(Duration(seconds: 3));

    if (age > 1 && age < 5) {
      return 4;
    } else if (age < 1) {
      return 0;
    } else {
      return 2;
    }
  }

  Stream<String> bark() async* {
    for (int i = 1; i < age; i++) {
      await Future.delayed(Duration(seconds: 2));
      yield 'Bark $i times';
    }
  }
}


// provider
  
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<Dog>(
          create: (context) => Dog(name: 'dog', breed: 'breed', age: 3),
        ),
        FutureProvider<int>(
          initialData: 0,
          create: (context) {
            final int dogAge =
                context.read<Dog>().age; 
                // 상위 프로바이더 값 사용 가능
            final babies = Babies(age: dogAge);
            return babies.getBabies();
          },
        ),
        StreamProvider(
	        initialData: 'Bark 0 times',
            create: (context) {
              final int dogAge = context.read<Dog>().age;
              final babies = Babies(age: dogAge * 2);
              return babies.bark();
            }
         ),
      ],
      child: MaterialApp(
        ...
    );
  }


// 사용하는 부분
Text(
  '- number of babies : ${context.watch<int>()}', 
  // future 함수의 리턴타입이 int이기 때문
),
Text(
  '- ${context.watch<String>()}',
  // stream 함수의 리턴타입이 string이기 때문,
  // 
),

Consumer 위젯

상태 관리와 빌드 최적화를 간단하게 처리할 수 있도록 도와주는 중요한 요소

  • 개발자가 provider.of를 통해서 타입T의 오브젝트를 얻을 필요가 없다는 말
  • consumer 위젯이 새로운 위젯에서 Provider.of를 호출하고 위젯에 빌드 구현을 위임함.
  • 빌더는 널이 아니어야하고 값이 변할 때마다 빌더가 호출되어야함.
  • 컨슈머 사용하면 리빌드 할 필요 없는 것도 리빌드 되는 거 아닌가?
    -> nullable 타입의 child 인자를 통해 해결
  class _MyHomePageState extends State<MyHomePage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Provider 08'),
      ),
      body: Consumer<Dog>(
        builder: (BuildContext context, Dog dog, Widget? child) {
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.min,
              children: [
                child!, 
  				// rebuild 하고 싶지 않음 - 이럴 때 사용하는 것이 builder의 세번째 인자 child
                SizedBox(height: 10.0),
                Text(
                  '- name: ${dog.name}',
                  style: TextStyle(fontSize: 20.0),
                ),
                SizedBox(height: 10.0),
                BreedAndAge(),
              ],
            ),
          );
        },
        child: Text(
          'i like dogs very much',
          style: TextStyle(fontSize: 20.0),
        ),
      ),
    );
  }
}

Selector 위젯

Consumer위젯과 거의 유사, Consumer보다 더 세세한 컨트롤할 수 있게 해주는 위젯
셀렉터 위젯을 사용할 때 selector 콜백에서 업데이트할 항목만 골라서
builder의 인자로 넘겨줄 수 있음 property가 많은 오브젝트라면 굉장히 좋은 솔루션


  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Provider 08'),
      ),
      body: Selector<Dog, String>( // <오브젝트타입, 선택할 프로퍼티의 타입>
        selector: (BuildContext context, Dog dog) => dog.name,
        builder: (BuildContext context, String name, Widget? child) {  
  		// Consumer와 마찬가지로 rebuild 제외할 child 지정 가능
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.min,
              children: [
                child!,
                SizedBox(height: 10.0),
                Text(
                  '- name: $name',
                  style: TextStyle(fontSize: 20.0),
                ),
                SizedBox(height: 10.0),
                BreedAndAge(),
              ],
            ),
          );
        },
        child: Text(
          'i like dogs very much',
          style: TextStyle(fontSize: 20.0),
        ),
      ),
    );
  }
profile
생각이 길면 용기는 사라진다.

0개의 댓글

관련 채용 정보