[Flutter] FutureProvider

겨레·2024년 7월 23일

① screen/future_provider_screen.dart 파일 생성하기




② HomeScreen에 FutureProviderScreen 등록

그러면 홈스크린 화면에서 FutureProviderScreen 버튼이 추가된 걸 확인할 수 있다.



③ FutureProvider 만들기

riverpod/future_provider.dart 파일 생성한다.
그리고 나는 List로 된 int를 리턴 해줄 거임.
(future_provider.dart에다가는 실제 async 요청을 가정해서 연습!)

자동완성되고... 완성 된 코드를 보면 기본 형태(구조)는 각각 provider들과 비슷하다는 걸 볼 수 있다.

다만, 각 provider의 제너릭( < > )에 들어가는 값과, 리턴을 주는 값(null 자리)이 다를 뿐!

  • future_provider.dart 코드
import 'package:flutter_riverpod/flutter_riverpod.dart';

final multiplesFutureProvider = FutureProvider<List<int>>((ref) => null);



④ async(비동기)로 만들어주기

async로 만들고 future.delayed로 2초 정도 기다렸다가,
List 형태의 숫자들을 반환하게 해볼거임.

  • future_provider.dart 코드
import 'package:flutter_riverpod/flutter_riverpod.dart';

final multiplesFutureProvider = FutureProvider<List<int>>((ref) async {
  await Future.delayed(
    const Duration(seconds: 2),
  );
  return [1, 2, 3, 4, 5];
});

⑤ FutureProviderScreen 수정하기

⑤-1. StatelessWidget을 ConsumerWidget으로 변경
FutureProviderScreen에서 StatelessWidget을 ConsumerWidget으로 변경해준다.

⑤-2. build 함수에 WidgetRef ref 추가
build 함수에 WidgetRef ref 파라미터를 추가해준다



⑥ ref.watch 해 주기

  • future_provider_screen.dart 코드
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_study/layout/defalut_layout.dart';
import 'package:riverpod_study/riverpod/future_provider.dart';

class FutureProviderScreen extends ConsumerWidget {
  const FutureProviderScreen({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    // watch 해주기
    final state = ref.watch(multiplesFutureProvider);

    return const DefalutLayout(
      title: 'FutureProviderScreen',
      body: Column(
        children: [],
      ),
    );
  }
}

지금까지 사용해본 provider에서는 동기 형태로 반환되는 상태였는데,
이번에는 FutureProvider에서는 2초간 비동기로 기다리는 시간이 있음!

그럼 이게 어떻게 처리되는걸까?
👉 .when 을 해 주면 자동완성으로 data, error, loading이라는 파라미터가 나옴

✔ data는 loading이 끝나가지고 데이터가 있을 때 실행는 함수
✔ error는 에러가 났을 때 실행되는 함수
✔ loading은 로딩되고 있을 때 실행되는 함수


  • future_provider_screen.dart 코드
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_study/layout/defalut_layout.dart';
import 'package:riverpod_study/riverpod/future_provider.dart';

class FutureProviderScreen extends ConsumerWidget {
  const FutureProviderScreen({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    // watch 해주기
    final state = ref.watch(multiplesFutureProvider);

    return DefalutLayout(
      title: 'FutureProviderScreen',
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          state.when(
            data: (data) {
              return Text(
                data.toString(),
                textAlign: TextAlign.center,
              );
            },
            error: (err, stack) => Text(
              err.toString(),
            ),
            loading: () => const Center(
              child: CircularProgressIndicator(),
            ),
          ),
        ],
      ),
    );
  }
}
 
  • data
    data에는 data가 들어가고, 이 data는 multiplesFutureProvider에서 반환받은 값임.
    그러니까 final state 이 state 값임!
  • error
    error에는 에러 내용, stack를 받을 수 있음.
    그리고 에러가 나면 text를 반환하도록 하겠음...

  • loading
    나는 loading 상태일 땐 아무 것도 파라미터에 받지 않고,
    그냥 CircularProgressIndicator 넣어줄거임.



앱 재실행 후에 FutureProviderScreen 버튼을 누르고 들어가면...

로딩이 2초간 되고...

이렇게 List 형태의 int 값이 반환되는 걸 확인할 수 있다.


error를 일부러 내보자!

앱을 재실행하고 FutureProviderScreen 버튼을 누르면...

똑같이 2초간 로딩되고...

에러 문구가 던져진다.

왜 이렇게 나오는걸까???

FutureProviderScreen 코드를 보면...
error가 발생했을 때, 에러 값을 그냥 Text에 넣고 String으로 반환하라고 했으니깐!



⑧ AsyncValue 상태로 들어오도록 하기

생각하고 있어야할 것!

final state 이 상태를 받았을 때, 이 상태는 AsyncValue라는 상태로 들어오게 된다!
그리고 이 AsyncValue는 .when 함수가 무조건 들어있음!

이 .when 함수로 data가 들어있을 때, error가 있을 때, loading 중일 때
경우를 따로 named Parameter로 함수를 써서 표현할 수 있다!


  • future_provider_screen.dart 코드
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_study/layout/defalut_layout.dart';
import 'package:riverpod_study/riverpod/future_provider.dart';

class FutureProviderScreen extends ConsumerWidget {
  const FutureProviderScreen({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    // watch 해주기
    final AsyncValue state = ref.watch(multiplesFutureProvider);

    return DefalutLayout(
      title: 'FutureProviderScreen',
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          state.when(
            data: (data) {
              return Text(
                data.toString(),
                textAlign: TextAlign.center,
              );
            },
            error: (err, stack) => Text(
              err.toString(),
            ),
            loading: () => const Center(
              child: CircularProgressIndicator(),
            ),
          ),
        ],
      ),
    );
  }
}

⑨ Exception 주석처리

에러를 다시 지우고 앱을 재실행하면 2초 뒤에 데이터가 다시 잘 나옴.
error로 간 게 아니라 data로 갔으니깐~

profile
호떡 신문지에서 개발자로 환생

0개의 댓글