
Flutter 앱을 개발하다 보면, 데이터의 상태를 효율적으로 관리하는 것이 성능과 유지보수성에 큰 영향을 미칩니다.
특히 Provider 패턴을 사용할 때 DB나 API 호출을 최소화하고, 이미 불러온 데이터를 메모리에서 가공해 재사용할 수 있다면 훨씬 효율적인 구조를 만들 수 있습니다.
이 글에서는 Getter를 활용해 Provider 내부 데이터를 안전하게 다루고, 불필요한 DB 호출을 줄이는 패턴을 구체적인 예제와 함께 살펴보겠습니다.
성능 향상을 위해 불필요한 중복 db/api를 호출하지 않고 provider의 메모리에 있는 데이터를 가공하여 재사용하는 것에 있습니다.
문제점
DB에서 데이터를 가져올 때 매번 새로 호출하면
네트워크 비용 증가, 응답지연에 따른성능 저하, api 호출 증가에 따른 유지비용 상승에 대한 문제가 있습니다.
해결점
이미 가져온 데이터가 있으면 provider의 private( _ ) 인스턴스변수에 저장 하고 getter를 사용하여 메모리에 있는 데이터를 가공하여 재활용합니다. 이렇게 하면 DB를 불필요하게 다시 호출하지 않아도 됩니다.
Getter는 객체의 프로퍼티를 읽는 (get)함수 입니다. 모든 인스턴스 변수는 암묵적으로 getter을 가집니다. get 키워드를 사용하여 getter을 구현하므로써 추가적인 프로퍼티를 생성 할 수 있습니다.
provider 내부에서 코드를 작성할때 인스턴스 변수는 private (_) 으로 작성하여 외부에서 접근 하지 못하게 합니다.
외부(UI)에서 데이터를 읽어야 할 때는 get을 통해 안전하게 열어주며, 가공된 형태로도 변환 할 수 있습니다.
이렇게 작성하면 외부에서 데이터를 마음대로 수정을 못해 안전하고
상태변화는 항상 provider 메서드에서만 일어나고 notifyListeners()로UI 업데이트가 가능해집니다.
인스턴스 변수는 private로 작성후 getter으로 안전하게 열어줍니다.
getter는 외부에서 읽기와 가공된 값을 보여줄 수 있습니다.
안정성 일관성 재상용성에 강점이 있습니다.
class Rectangle {
double left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// right, bottom 이라는 두 개의 계산된 프로퍼티 정의.
double get right => left + width;
set right(double value) => left = value - width;
double get bottom => top + height;
set bottom(double value) => top = value - height;
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
// 인스턴스 변수(실제 데이터를 저장하는 공간)
List<User> _userList = [];
// getter 외부에서 읽기를 위한 객체의 프로퍼티
List<User> get userList => _userList;
// 가공된 getter user의 uuid 만 뽑아서 중복제거,리스트 반환
// 추가적인 프로퍼티 생성
// 활용도가 많은 코드입니다.
List<String> get uniqueUserIds =>
_userList
.map((user) => user.uuid)
.toSet()
.toList();
// 데이터 호출, 상태 변경 메서드
// 인스턴스 변수를 갱신
// projectId에 해당하는 userList
Future<void> getUserList(int projectId) async {
_isLoading = true;
_error = null;
notifyListeners();
final user = await getUserListUseCase(
projectId,
);
user.fold((left) {
_userList = [];
_error = left.message;
}, (right) => _userList = right);
_isLoading = false;
notifyListeners();
}
// UI에서 Getter로 user 이름 리스트 (for문 기반)
// 페이지 진입시 UserProvider의 필요한 매게변수를 외부에서 받아야합니다.
Widget build(BuildContext context) {
return Consumer<UserProvider>(
builder: (context, provider, _) {
final users = provider.userList;
// !!!! provider.userList는 UserProvider 파일 내부에서 정의된 getter입니다.
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return Text(users[index].name);
},
);
},
);
}
Provider에서 Getter를 활용하는 것은 단순한 코드 스타일 문제가 아니라, 앱의 성능과 안정성을 모두 향상시키는 핵심 패턴입니다.
DB 호출을 최소화하고, 메모리에 있는 데이터를 효율적으로 가공해 재사용함으로써 네트워크 비용 절감, 응답 속도 개선, 유지보수성 향상을 동시에 달성할 수 있습니다.
결국 이 접근법은 “데이터는 Provider가 관리하고, UI는 Getter로 읽는다”는 원칙으로 요약됩니다.
이 패턴을 프로젝트 전반에 일관되게 적용하면, Flutter 앱의 성능은 물론 구조적 안정성도 한 단계 끌어올릴 수 있을 것입니다.
UI 페이지 진입 시 provider의 비동기 호출(getUserList(projectId))을
initState()나 Future.microtask()에서 안전하게 처리하는 방법도
다음 포스트에서 함께 다룰 예정입니다.
_userList)userList)userIdList)getUserList)