보통 Provider는 상태관리 용도로만 많이 알고있지만, 사실 Provider의 주요 용도는 두가지 이다.
1. DI 용도
2. 상태관리 용도
쉽게 말하자면, 우리가 흔히 상태관리 용도로 사용하는 Provider는,
먼저 DI를 통해 상태 객체를 위젯 트리에 주입한 후,
여러 위젯에서 이를 가져다 쓰며 상태를 구독하고, 변경에 따라 UI를 갱신할 수 있도록 하는 방식이다.
1️⃣ ApiService (의존성 대상)
class ApiService {
Future<String> fetchUserName() async {
await Future.delayed(Duration(seconds: 1));
return "홍길동";
}
}
2️⃣ UserRepository (비즈니스 계층)
class UserRepository {
final ApiService apiService;
UserRepository(this.apiService);
Future<String> getUserName() => apiService.fetchUserName();
}
3️⃣ UserProvider (ChangeNotifier)
class UserProvider with ChangeNotifier {
final UserRepository userRepository;
String _userName = "";
String get userName => _userName;
UserProvider(this.userRepository);
Future<void> loadUserName() async {
_userName = await userRepository.getUserName();
notifyListeners();
}
}
4️⃣ main.dart (DI 트리 구성)
void main() {
runApp(
MultiProvider(
providers: [
Provider<ApiService>(
create: (_) => ApiService(),
),
Provider<UserRepository>(
create: (context) {
final api = Provider.of<ApiService>(context, listen: false);
혹은
final api = context.read<ApiService>();
return UserRepository(api);
},
),
ChangeNotifierProvider<UserProvider>(
create: (context) {
final repo = Provider.of<UserRepository>(context, listen: false);
혹은
final repo = context.read<UserRepository>();
return UserProvider(repo);
},
),
],
child: const MyApp(),
),
);
}
provider.of(context)
=> 위젯 트리 상단에 주입된 객체를 직접 꺼내서 사용할 수 있게 해주는 메서드. 즉, 먼저 주입된 ApiService를 직접 꺼내서 사용
context.read
=> Provider.of와 동일하지만,보통 실무에서는 가독성과 간결성 때문에 context.read를 더 자주 쓴다.
listen : false
=> 상태관리를 위한 Provider의 값이 바뀌었을때 위젯을 리빌드 할지말지 결정하는 값으로 보면 된다.
ChangeNotifierProvider
=> ChangeNotifier를 사용하는 객체를 Flutter 위젯 트리에 주입하고,
그 객체의 상태가 바뀌면 자동으로 리스닝 중인 위젯들을 리빌드해주는 Provider