-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
cache.dart
135 lines (122 loc) · 4.71 KB
/
cache.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
part of katana_scoped.value;
/// Provides an extension method for [Ref] to perform caching.
///
/// キャッシュを行うための[Ref]用の拡張メソッドを提供します。
extension RefCacheExtensions on Ref {
/// Caches and stores the value returned by [callback].
///
/// If [keys] is passed a value different from the previous value, [callback] is executed again and the value is updated.
///
/// If [name] is specified, it is saved as a separate type. If [keys] is changed, the previous state is discarded, but if [name] is changed, it is kept as a separate state.
///
/// If you want [ScopedValue] to be automatically disposed of when it is no longer referenced by any widget, set [autoDisposeWhenUnreferenced] to `true`.
///
/// [callback]で返される値をキャッシュして保存します。
///
/// [keys]が前の値と違う値が渡された場合、再度[callback]が実行され値が更新されます。
///
/// [name]を指定すると別のタイプとして保存されます。[keys]を変えた場合は以前の状態は破棄されますが、[name]を変えた場合は別々の状態として保持されます。
///
/// [ScopedValue]がどのウィジェットにも参照されなくなったときに自動的に破棄させたい場合は[autoDisposeWhenUnreferenced]を`true`にしてください。
T cache<T>(
T Function(Ref ref) callback, {
List<Object> keys = const [],
String? name,
bool autoDisposeWhenUnreferenced = false,
}) {
return getScopedValue<T, _CacheValue<T>>(
(ref) => _CacheValue<T>(
callback: () => callback(ref),
keys: keys,
ref: ref,
autoDisposeWhenUnreferenced: autoDisposeWhenUnreferenced,
),
listen: false,
name: name,
);
}
}
/// Provides an extension method for [RefHasPage] to perform caching.
///
/// キャッシュを行うための[RefHasPage]用の拡張メソッドを提供します。
extension RefHasPageCacheExtensions on RefHasPage {
/// Caches and stores the value returned by [callback].
///
/// If [keys] is passed a value different from the previous value, [callback] is executed again and the value is updated.
///
/// If [name] is specified, it is saved as a separate type. If [keys] is changed, the previous state is discarded, but if [name] is changed, it is kept as a separate state.
///
/// If you want [ScopedValue] to be automatically disposed of when it is no longer referenced by any widget, set [autoDisposeWhenUnreferenced] to `true`.
///
/// [callback]で返される値をキャッシュして保存します。
///
/// [keys]が前の値と違う値が渡された場合、再度[callback]が実行され値が更新されます。
///
/// [name]を指定すると別のタイプとして保存されます。[keys]を変えた場合は以前の状態は破棄されますが、[name]を変えた場合は別々の状態として保持されます。
///
/// [ScopedValue]がどのウィジェットにも参照されなくなったときに自動的に破棄させたい場合は[autoDisposeWhenUnreferenced]を`true`にしてください。
T cache<T>(
T Function(Ref ref) callback, {
List<Object> keys = const [],
String? name,
bool autoDisposeWhenUnreferenced = false,
}) {
return page.cache<T>(
callback,
keys: keys,
name: name,
autoDisposeWhenUnreferenced: autoDisposeWhenUnreferenced,
);
}
}
@immutable
class _CacheValue<T> extends ScopedValue<T> {
const _CacheValue({
required this.callback,
required this.keys,
required this.ref,
this.autoDisposeWhenUnreferenced = false,
});
final T Function() callback;
final List<Object> keys;
final Ref ref;
final bool autoDisposeWhenUnreferenced;
@override
ScopedValueState<T, ScopedValue<T>> createState() => _CacheValueState<T>();
}
class _CacheValueState<T> extends ScopedValueState<T, _CacheValue<T>> {
_CacheValueState();
late T _value;
@override
bool get autoDisposeWhenUnreferenced => value.autoDisposeWhenUnreferenced;
@override
void initValue() {
super.initValue();
_value = value.callback();
final ref = value.ref;
if (ref is ListenableRef) {
ref.addListener(_handledOnUpdateByRef);
}
}
@override
void didUpdateValue(_CacheValue<T> oldValue) {
super.didUpdateValue(oldValue);
if (!equalsKeys(value.keys, oldValue.keys)) {
_value = value.callback();
}
}
void _handledOnUpdateByRef() {
_value = value.callback();
setState(() {});
}
@override
void dispose() {
super.dispose();
final ref = value.ref;
if (ref is ListenableRef) {
ref.removeListener(_handledOnUpdateByRef);
}
}
@override
T build() => _value;
}