FutureProvider

샤워실의 바보·2024년 2월 21일
0

Provider Flutter

목록 보기
3/3
post-thumbnail
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'models/babies.dart';
import 'models/dog.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<Dog>(
          create: (context) => Dog(name: 'dog06', breed: 'breed06', age: 3),
        ),
        FutureProvider<int>(
          initialData: 0,
          create: (context) {
            final int dogAge = context.read<Dog>().age;
            final babies = Babies(age: dogAge);
            return babies.getBabies();
          },
        ),
      ],
      child: MaterialApp(
        title: 'Provider 06',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const MyHomePage(),
      ),
    );
  }
}

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

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Provider 05'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              '- name: ${context.watch<Dog>().name}',
              style: TextStyle(fontSize: 20.0),
            ),
            SizedBox(height: 10.0),
            BreedAndAge(),
          ],
        ),
      ),
    );
  }
}

class BreedAndAge extends StatelessWidget {
  const BreedAndAge({
    Key? key,
  }) : super(key: key);

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(
          '- breed: ${context.select<Dog, String>((Dog dog) => dog.breed)}',
          style: TextStyle(fontSize: 20.0),
        ),
        SizedBox(height: 10.0),
        Age(),
      ],
    );
  }
}

class Age extends StatelessWidget {
  const Age({
    Key? key,
  }) : super(key: key);

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(
          '- age: ${context.select<Dog, int>((Dog dog) => dog.age)}',
          style: TextStyle(fontSize: 20.0),
        ),
        SizedBox(height: 10.0),
        Text(
          '- number of babies: ${context.read<int>()}',
          style: TextStyle(fontSize: 20.0),
        ),
        SizedBox(height: 20.0),
        ElevatedButton(
          onPressed: () => context.read<Dog>().grow(),
          child: Text(
            'Grow',
            style: TextStyle(fontSize: 20.0),
          ),
        ),
      ],
    );
  }
}

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;
    }
  }

위의 코드는 Flutter에서 provider 패키지를 사용해 상태 관리를 구현하는 방법을 보여줍니다. 특히, ChangeNotifierProviderFutureProviderMultiProvider 안에서 함께 사용하는 예시를 제시합니다. 여기서 ChangeNotifierProviderDog 객체를 관리하며, FutureProvider는 비동기 작업을 통해 데이터를 제공합니다. 이 예시에서는 비동기 작업으로 Dog의 나이에 기반한 "babies"의 수를 가져옵니다.

ChangeNotifierProvider

  • Dog 클래스의 인스턴스를 생성하고 제공합니다. Dog 클래스는 ChangeNotifier를 확장(extends)하며, 이름(name), 품종(breed), 나이(age) 속성을 가지고 있고, 나이를 증가시키는 grow 메서드를 포함합니다.
  • Dog 객체의 변경사항은 notifyListeners() 메서드 호출을 통해 구독자에게 알립니다.

FutureProvider

  • FutureProvider는 비동기 작업의 결과를 위젯 트리에 제공합니다. 이 예시에서는 Dog의 나이를 기반으로 "babies"의 수를 계산하는 비동기 작업을 수행합니다.
  • initialData 속성에 0을 설정함으로써, 비동기 작업이 완료되기 전까지 "babies"의 수의 초기 값으로 0을 사용합니다.

MultiProvider

  • 여러 개의 프로바이더를 동시에 사용할 수 있도록 해줍니다. 이 예시에서는 ChangeNotifierProviderFutureProvider 두 가지를 사용합니다.

위젯 트리 내에서의 데이터 접근

  • MyHomePage, BreedAndAge, Age 위젯에서 context.watch<T>(), context.select<T, R>(), 그리고 context.read<T>() 메서드를 사용하여 Dog 객체와 "babies"의 수에 접근합니다.
  • watchselect를 사용하여 Dog 객체의 속성이 변경될 때마다 관련된 위젯을 다시 빌드하도록 합니다. 이는 사용자 인터페이스(UI)가 최신 상태를 반영하도록 보장합니다.
  • readFutureProvider에서 제공하는 "babies"의 수를 읽어옵니다. read 메서드는 데이터를 읽을 때 사용되며, 이 경우 데이터의 변경을 감지하여 위젯을 재빌드하지 않습니다.

주요 개념

  • 상태 관리: provider 패키지를 사용하여 앱의 상태를 효율적으로 관리합니다.
  • 비동기 처리: FutureProvider를 통해 비동기 작업의 결과를 UI에 반영합니다.
  • 데이터 접근 및 감시: watch, select, read 메서드를 사용하여 상태 객체에 접근하고, 필요한 경우 위젯을 재빌드합니다.

이 코드는 provider 패키지를 활용한 상태 관리와 비동기 작업의 결과를 UI에 통합하는 방법을 보여주며, Flutter 앱 개발에서 중요한 패턴 중 하나를 나타냅니다.

위의 Babies 클래스는 age를 매개변수로 받아, 해당 나이에 따라 다른 "babies"의 수를 비동기적으로 반환하는 예시입니다. getBabies 메서드는 나이(age)에 따라 조건부 로직을 통해 결정된 "babies"의 수를 비동기적으로 반환합니다. 이 메서드는 Future<int> 타입을 반환하며, 이는 FutureProvider에 의해 사용됩니다.

Babies 클래스와 FutureProvider

FutureProviderBabies 인스턴스의 getBabies 메서드를 호출하여, 반환된 "babies"의 수를 앱의 다른 부분에서 사용할 수 있게 해줍니다. 이 과정은 다음과 같이 이루어집니다:

  1. FutureProvidercreate 콜백에서, Babies 클래스의 인스턴스가 생성됩니다. 이때 Dog 객체의 나이(age)가 Babies 클래스의 생성자에 전달됩니다.
  2. 생성된 Babies 인스턴스에 대해 getBabies 메서드가 호출됩니다. 이 메서드는 비동기적으로 "babies"의 수를 계산하고 반환합니다.
  3. FutureProvidergetBabies 메서드의 결과를 앱 내에서 사용할 수 있게 해줍니다. 이때 initialData를 통해 비동기 작업이 완료되기 전까지 사용될 초기 데이터를 설정할 수 있습니다.

getBabies 메서드의 비동기 처리

getBabies 메서드는 Future.delayed를 사용하여 3초의 지연을 가진 후, 나이(age)에 기반한 조건에 따라 다음과 같이 "babies"의 수를 결정합니다:

  • 나이가 1살 초과이고 5살 미만이면, "babies"의 수로 4를 반환합니다.
  • 나이가 1살 이하이면, "babies"의 수로 0를 반환합니다.
  • 그 외의 경우, "babies"의 수로 2를 반환합니다.

이 예제에서 FutureProviderBabies 클래스의 조합은 비동기 작업을 통해 동적 데이터를 처리하고, 그 결과를 앱의 UI에 반영하는 방법을 보여줍니다. 특히, FutureProviderBabies 클래스의 getBabies 메서드로부터 반환된 "babies"의 수를 앱의 상태로 관리하며, 이를 위젯 트리에서 필요한 곳에 제공합니다.

이러한 방식은 Flutter에서 비동기 작업의 결과를 효과적으로 관리하고, UI가 해당 데이터의 최신 상태를 반영하도록 하는 데 매우 유용합니다. 사용자에게 보여지는 데이터가 비동기 작업에 의해 결정되는 경우, FutureProvider와 같은 패턴을 사용함으로써 앱의 반응성과 사용자 경험을 향상시킬 수 있습니다.

profile
공부하는 개발자

0개의 댓글