성능 최적화하기
지금까지 살펴본 내용을 통해 이미 모든 기능을 갖춘 애플리케이션을 구축할 수 있습니다. 하지만 성능과 관련하여 궁금한 점이 있을 수 있습니다.
이 페이지에서는 코드를 최적화할 수 있는 몇 가지 팁과 요령을 다룰 것입니다.
최적화를 수행하기 전에 애플리케이션을 벤치마킹(benchmark)해야 합니다. 최적화로 인한 복잡성 증가는 소소한 이득에 비해 가치가 없을 수 있습니다.
"select"을 사용하여 위젯/provider 다시 빌드하는 것을 필터링합니다.
기본적으로 ref.watch
를 사용하면 객체의 어떠한(any) 프로퍼티라도 변경될때마다, consumers/providers가 다시 빌드하는 것을 보셨을 것입니다.
예를 들어, User
를 watch하고 "name"만 사용해도 'age'가 변경되면 Consumer는 여전히 다시 빌드됩니다.
그러나 일부 속성만 사용하는 consumer가 있는 경우, 다른 속성이 변경될 때 위젯을 다시 빌드하지 않고 싶을 수 있습니다.
이는 provider의 select
기능을 사용하여 수행할 수 있습니다.
이렇게 하면 ref.watch
는 더 이상 전체 객체를 반환하지 않고 선택된 프로퍼티만 반환합니다.
그리고 consumer/provider는 이제 선택된 프로퍼티가 변경되는 경우에만 다시 빌드됩니다.
class User {
late String firstName, lastName;
}
User example(Ref ref) => User()
..firstName = 'John'
..lastName = 'Doe';
class ConsumerExample extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
// 아래처럼 작성하는 대신:
// String name = ref.watch(provider).firstName!;
// 이렇게 작성할 수 있습니다:
String name = ref.watch(exampleProvider.select((it) => it.firstName));
// 그러면 위젯이 'firstName'에 대한 변경 사항만 수신하게 됩니다.
return Text('Hello $name');
}
}
select
는 원하는 횟수만큼 호출할 수 있습니다.
원하는 속성당 한 번씩 자유롭게 호출할 수 있습니다.
선택된 프로퍼티는 변경되지 않을 것으로 예상됩니다.
List
를 반환한 다음 해당 리스트를 변경해도 리빌드가 트리거되지 않습니다.
select
을 사용하면 무효(invididual) 읽기 작업 속도가 약간 느려지고, 코드의 복잡성이 약간 증가합니다.
이러한 "다른 속성"이 거의 변경되지 않는 경우에는 사용할 가치가 없을 수 있습니다.
Selecting asynchronous properties
다른 provider를 수신하는 provider를 최적화하려는 경우 다른 provider가 비동기식일 가능성이 있습니다.
일반적으로는 ref.watch(anotherProvider.future)
를 사용해 값을 가져옵니다.
이슈는 select
가 기다릴수(await) 없는 AsyncValue
에 적용된다는 것입니다.
이를 위해 selectAsync
를 대신 사용할 수 있습니다.
이 함수는 비동기 코드에 고유하며, provider가 내보낸 데이터에 대해 select
연산을 수행할 수 있습니다.
사용법은 select
와 비슷하지만 대신 Future
를 반환합니다:
Object? example(Ref ref) async {
// user를 사용할 수 있을 때까지 기다렸다가 "firstName" 속성만 수신합니다.
final firstName = await ref.watch(
userProvider.selectAsync((it) => it.firstName),
);
// TODO 다른 항목을 가져오기위해 "firstName"을 사용합니다.
}