이전 포스팅에 이어서 위젯과 위젯간 값을 전달할 때 Provider를 사용하여 전역변수를 공유하는 방법을 알아보겠다.
2. Provider를 사용하여 전역변수를 공유하는 방법
2-1. pubspec.yaml에 Provider 패키지 의존성 추가하기
Provider 의존성 추가를 위해 아래 URL에 접속하여 버전 등을 복사한다.
https://pub.dev/packages/provider
provider | Flutter Package
A wrapper around InheritedWidget to make them easier to use and more reusable.
pub.dev
포스팅 작성일 기준 최신버전은 provider 6.0.5 버전이 최신이다.
provider: ^6.0.5
dependencies에 다음과 같이 추가하고 Pub get을 실행한다.
dependencies:
flutter:
sdk: flutter
provider: ^6.0.5
2-2. 전역변수를 담을 클래스 생성
전역변수를 보관할 클래스를 만들어준다. GlobalStore라는 이름으로 만들어주었다.
여기에 몇가지 변수를 선언해준다.
import 'package:flutter/material.dart';
class GlobalStore extends ChangeNotifier{
String str = "Store입니다.";
List<String> arr = ["Store1", "Store2"];
}
2-3. 전역변수 사용하기
이 클래스에 담은 변수를 다른 위젯에서 공유하려면 몇가지 절차가 필요하다.
우선 위에서 설치한 provider를 import 해준다.
import 'package:provider/provider.dart';
우선 이 앱을 실행시켜주는 main 함수에 MultiProvider를 추가해야 한다.
그리고 providers에 ChangeNotifierProvider로 GlobalStore를 전달해준다.
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (create) => GlobalStore())
],
child: MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("위젯간 값 전달하기"),
),
body: MyApp()
)
),
)
);
}
이렇게 하면 사용 준비는 끝났다.
MyApp 위젯에서 GlobalStore에 선언된 변수 하나를 사용하기 위해 Text 위젯을 하나 넣어보았다.
class _MyAppState extends State<MyApp> {
int firstChildValue = 1;
int secondChildValue = 2;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("GlobalStore에서 끌어다 쓸 값 자리"),
FirstChild(firstChildValue: firstChildValue),
SecondChild(secondChildValue: secondChildValue),
],
),
);
}
}
GlobalStore에 있는 값을 사용하기 위해 클래스에 접근하여 값을 가져와야 한다.
Text(context.read<GlobalStore>().str)
read 메소드는 provider가 지원하는 메소드이다. 제네릭으로 GlobalStore을 걸어주고, 그 안에 선언된 str을 사용할 수 있다.
앱을 Reload 해보면 잘 들어가는 것을 확인할 수 있다.
GlobalStore에서 선언한 배열의 0번째, 1번째 요소도 쉽게 가져올 수 있다.
class _FirstChildState extends State<FirstChild> {
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("${widget.firstChildValue ?? 'n'}번째 자식 위젯"),
],
),
Column(
children: [
Text("Global Store : ${context.read<GlobalStore>().arr[0]}"),
Text("Global Store : ${context.read<GlobalStore>().arr[1]}"),
],
)
],
);
}
}
2-4. GlobalStore로 HTTP 요청 데이터 사용하기
비동기로 처리되는 http 요청을 전역변수로 관리하기 위해 전역변수에 함수를 만들어두고 페이지가 로드될 때 함수를 호출할 수 있다.
우선 http 요청을 사용하기 위해 pubspec.yaml 파일을 열고 의존성을 추가해준다. 그리고 Pub get을 실행한다.
http: ^0.13.5
http | Dart Package
A composable, multi-platform, Future-based API for HTTP requests.
pub.dev
GlobalStore에서 http 패키지를 import하고, 요청 후 데이터를 받아올 배열을 선언해준다.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class GlobalStore extends ChangeNotifier{
List<dynamic> httpResponseData = [];
String str = "Store입니다.";
List<String> arr = ["Store1", "Store2"];
}
클래스 내부에 http 요청을 보낼 함수를 선언해준다.
void getHttpRequestData () async {
var request = await http.get(Uri.parse("https://jsonplaceholder.typicode.com/posts"));
var parseData = jsonDecode(request.body);
httpResponseData = parseData;
}
이 함수를 위젯의 initState에서 호출하여 전역으로 선언한 리스트에 결과가 추가되도록 해준다.
class _MyAppState extends State<MyApp> {
int firstChildValue = 1;
int secondChildValue = 2;
@override
void initState() {
super.initState();
context.read<GlobalStore>().getHttpRequestData();
}
// 생략
}
이제 위젯을 빌드하는 함수에 전역으로 선언한 리스트를 지역변수로 넣어주고, 해당 지역변수를 참조하여 값을 확인할 수 있도록 리스트뷰를 만든다.
@override
Widget build(BuildContext context) {
final httpResponseData = context.watch<GlobalStore>().httpResponseData;
return Center(
child: SizedBox(
width: double.infinity,
child: httpResponseData.isEmpty
? Text("loading...", textAlign: TextAlign.center,)
: ListView.builder(
itemCount: httpResponseData.length,
itemBuilder: (BuildContext c, int i) {
return Text(httpResponseData[i]["title"]);
}
),
),
);
}
이렇게만 해주면 화면에서는 계속 "loading..."만 보이게 된다.
가장 중요한 결정적인 처리를 하나 해주어야 하는데, 전역으로 선언된 http 요청 함수에서 요청 후 값이 변경되었다는 상태를 알려주어야 한다.
이를 위해 함수의 마지막에 notifyListener를 호출해야 한다.
void getHttpRequestData () async {
var request = await http.get(Uri.parse("https://jsonplaceholder.typicode.com/posts"));
var parseData = jsonDecode(request.body);
httpResponseData = parseData;
notifyListeners();
}
이렇게 하면 함수를 통해 전역으로 선언한 리스트의 내용이 바뀌었을 때, 위젯을 리렌더링 하게 된다.
'Flutter | Dart' 카테고리의 다른 글
[Flutter] 위젯과 위젯간 값을 전달하는 방법(1) (부모-자식 관계의 위젯) (0) | 2023.04.09 |
---|---|
[Flutter] fluent_ui로 DatePicker 구현하기 (1) | 2023.03.07 |