본문 바로가기
Dart (Flutter)

[Flutter] Provider

by llHoYall 2023. 8. 12.

Provider는 application 전역에 걸쳐 상태를 공유하는 방법 중 하나입니다.

상속 관계가 깊을 경우 정보 공유를 하려면 부모 자식 간에 계속 해서 정보를 전달해야하는 불편함이 있는 데, 이를 해소해 줄 수 있습니다.

뭐 다른 framework들을 사용해 봤다면 익숙한 개념이실 거에요.

Provider는 여러 가지 provider를 제공해 주는 데, 공식 페이지 설명이 영 괴상망측해서 알아보기가 힘드셨을 거에요. (제가 그랬거든요...)

이번 포스팅에서는 기본적으로 쉽게 사용하실 수 있는 방법을 알려드릴게요.

Install Package

먼저, 필요한 package를 설치해 줍니다.

pubspec.yaml 파일에 다음의 내용을 추가해 줍니다.

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  provider: ^6.0.5

이제 해당 패키지를 가져오면 준비가 끝납니다.

$ flutter pub get

Create Shared Item

이제, 공유할 데이터들을 담고 있는 class를 정의해 줍니다.

import 'package:flutter/material.dart';

class Cart extends ChangeNotifier {
  String _item = 'none';

  String get item => _item;

  set item(String newItem) {
    _item = newItem;
    notifyListeners();
  }
}

저는 이름을 Cart 라고 지어 봤어요. 공유할 값은 String 값이고, 이름은 item이라고 지어줬고요.

Getter와 setter도 간단히 만들어 주었습니다.

ChangeNotifier를 상속받아 setter에서 값을 원하는 곳에 알려줄 수 있도록 notifyListeners() 함수를 호출하도록 했습니다.

요 2개가 사실상 핵심입니다.

Provide Item

이제 이것을 application 전역적으로 공유를 해봅니다.

Widget tree의 최상위에서 제공을 해주면 됩니다.

import 'package:flutter/material.dart';

import 'package:provider/provider.dart';

import 'package:test/cart.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (context) => Cart(),
        ),
      ],
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: true,
        ),
        home: const Home(),
      ),
    );
  }
}

필요한 것들을 import해준 후, MultiProvider로 감싸줍니다. 이름에서 느껴지듯이, provider가 여럿 있어도 모두 공유해줄 수 있어요.

provider들을 ChangeNotifierProvider로 설정을 해 줍니다.

create property에 우리가 만들었던 Cart를 넣어줬어요.

child 부분은 늘 보던 MaterialApp이죠? ㅎㅎ

Change Value of Shared Item

이제, 실제 app의 UI가 될 Home 부분을 만들어 볼게요.

class Home extends StatelessWidget {
  const Home({super.key});

  @override
  Widget build(BuildContext context) {
    final providerCart = Provider.of<Cart>(context);
    return Scaffold(
      appBar: AppBar(title: const Text('Provder Example')),
      body: Column(
        children: [
          Text(providerCart.item),
          ElevatedButton(
            onPressed: () {
              providerCart.item = 'Test Item';
            },
            child: const Text('Update Cart'),
          ),
          const Page(),
        ],
      ),
    );
  }
}

Provider.of는 공유된 값을 제어할 수 있게 해줍니다.

예제를 보시면 Text widget을 통해 현재 공유된 값을 가져오고, ElevatedButton을 통해 공유된 값을 변경하고 있죠?

보시자마자 쉽게 아실 거에요.

Get the Shared Item

이번에는 Page widget을 만들어 값을 가져오기만 해볼게요.

class Page extends StatelessWidget {
  const Page({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer<Cart>(
      builder: (context, value, child) => Text(value.item),
    );
  }
}

Consumer를 사용해서 값을 가져오면 됩니다.

이제, 테스트를 해봐야죠?

Update Cart button을 누르면 공유된 값이 바뀌고 즉시 이 값을 사용하고 있는 곳에 변경 사항이 반영됩니다.

Wrap Up

이번에는 application을 개발하면 필연적으로 필요해지는 widget tree 전역에서 데이터를 공유할 수 있는 기능을 제공해주는 provider에 대해 살펴보았습니다.

아주 간단하게 사용할 수 있는 방법에 대해 소개시켜드렸으니 참고하셔서 잘 사용하셨으면 좋겠네요. ^^

댓글