Add freshness caching to prevent redundant method executions within a time period
This skill adds freshness caching to prevent redundant method executions within a time period.
Adds the fresh parameter to a mix() call so that:
Ask the user which Cubit method needs freshness caching, or identify methods that:
Add fresh: fresh to the mix() call:
import 'package:bloc_superpowers/bloc_superpowers.dart';
class UserCubit extends Cubit<User> {
UserCubit() : super(User());
void loadData() => mix(
key: this,
fresh: fresh, // Add this line (default: 1 second)
() async {
final user = await api.loadUser();
if (user == null) throw UserException('Failed to load user');
emit(user);
},
);
}
The default freshness period is 1 second. Customize based on how often data changes:
void loadData() => mix(
key: this,
fresh: fresh(freshFor: 5.sec), // Data valid for 5 seconds
() async {
final user = await api.loadUser();
emit(user);
},
);
fresh // 1 second (default)
fresh(freshFor: 5.sec) // 5 seconds
fresh(freshFor: 30.sec) // 30 seconds
fresh(freshFor: 5.minutes) // 5 minutes
fresh(freshFor: 1.hours) // 1 hour
Allow bypassing freshness with a parameter:
void loadData({bool force = false}) => mix(
key: this,
fresh: fresh(
freshFor: 5.sec,
ignoreFresh: force, // When true, ignores freshness
),
() async {
final data = await api.getData();
emit(data);
},
);
// Normal call - respects freshness
cubit.loadData();
// Force refresh - ignores freshness
cubit.loadData(force: true);
Track freshness separately for different parameters:
void loadUser(String userId) => mix(
key: this, // State tracking uses UserCubit
fresh: fresh(
key: (UserCubit, userId), // Freshness tracked per userId
freshFor: 5.sec,
),
() async {
final user = await api.loadUser(userId);
emit(state.copyWith(users: {...state.users, userId: user}));
},
);
With this setup:
context.isWaiting(UserCubit) shows loading for any usercubit.loadData(); // ✓ Executes, data loaded, marked fresh
// ... 2 seconds later (within 5 sec freshness) ...
cubit.loadData(); // ✗ Skipped, data still fresh
// ... 4 more seconds later (total 6 sec, past freshness) ...
cubit.loadData(); // ✓ Executes, data reloaded
If the method fails, freshness is not set. This allows immediate retry:
cubit.loadData(); // ✗ Fails with error
cubit.loadData(); // ✓ Executes immediately (not marked fresh due to error)
Prevent reloading when navigating back to a screen:
void loadScreenData() => mix(
key: this,
fresh: fresh(freshFor: 30.sec),
() async {
final data = await api.getScreenData();
emit(data);
},
);
void loadProducts({bool force = false}) => mix(
key: this,
fresh: fresh(freshFor: 1.minutes, ignoreFresh: force),
() async {
final products = await api.getProducts();
emit(state.copyWith(products: products));
},
);
// In widget
RefreshIndicator(
onRefresh: () => cubit.loadProducts(force: true),
child: ProductList(),
)
void loadData() => mix(
key: this,
fresh: fresh(freshFor: 10.sec),
retry: retry,
() async {
final data = await api.getData();
emit(data);
},
);
void loadData() => mix(
key: this,
fresh: fresh(freshFor: 5.sec),
nonReentrant: nonReentrant,
retry: retry,
() async {
final data = await api.getData();
emit(data);
},
);
Clear freshness manually when needed:
// Clear freshness for a specific key
Superpowers.removeFreshKey(UserCubit);
Superpowers.removeFreshKey((UserCubit, userId));
// Clear all freshness keys
Superpowers.removeAllFreshKeys();
Use cases for manual clearing:
Good candidates:
Consider freshness duration:
Not recommended:
class ProductCubit extends Cubit<ProductState> {
ProductCubit() : super(const ProductState());
// Products stay fresh for 1 minute
void loadProducts({bool force = false}) => mix(
key: this,
fresh: fresh(freshFor: 1.minutes, ignoreFresh: force),
retry: retry,
() async {
final products = await api.getProducts();
emit(state.copyWith(products: products));
},
);
// Product details fresh per product ID
void loadProductDetails(String productId) => mix(
key: (ProductDetails, productId),
fresh: fresh(freshFor: 30.sec),
() async {
final details = await api.getProductDetails(productId);
emit(state.copyWith(
productDetails: {...state.productDetails, productId: details},
));
},
);
}
Ask the user:
下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer