feed-datasource-expert — community feed-datasource-expert, watch_it, community, ide skills

v1.0

About this Skill

Perfect for Frontend Agents needing advanced paginated list/feed widget capabilities with ValueNotifiers and Commands. Expert guidance on implementing paginated feeds and infinite scroll in Flutter using FeedDataSource and PagedFeedDataSource patterns. Covers base feed data source, cursor-based pagination, auto-pagina

flutter-it flutter-it
[0]
[0]
Updated: 3/12/2026

Killer-Skills Review

Decision support comes first. Repository text comes second.

Reference-Only Page Review Score: 7/11

This page remains useful for teams, but Killer-Skills treats it as reference material instead of a primary organic landing page.

Original recommendation layer Concrete use-case guidance Explicit limitations and caution Locale and body language aligned
Review Score
7/11
Quality Score
47
Canonical Locale
en
Detected Body Locale
en

Perfect for Frontend Agents needing advanced paginated list/feed widget capabilities with ValueNotifiers and Commands. Expert guidance on implementing paginated feeds and infinite scroll in Flutter using FeedDataSource and PagedFeedDataSource patterns. Covers base feed data source, cursor-based pagination, auto-pagina

Core Value

Empowers agents to create reactive, data-intensive applications with seamless pagination and entity lifecycle management using proxy patterns, ValueNotifiers, and separate commands like updateDataCommand and requestNextPageCommand.

Ideal Agent Persona

Perfect for Frontend Agents needing advanced paginated list/feed widget capabilities with ValueNotifiers and Commands.

Capabilities Granted for feed-datasource-expert

Implementing infinite scroll for dynamic content feeds
Building paginated lists with auto-pagination triggers
Managing entity lifecycles with proxy patterns for data-intensive applications

! Prerequisites & Limits

  • Requires integration with ValueNotifiers and Commands
  • Auto-pagination triggers at items.length - 3, not at the last item
  • Proxies must be released after replacing with new ones during refresh

Why this page is reference-only

  • - The underlying skill quality score is below the review floor.

Source Boundary

The section below is imported from the upstream repository and should be treated as secondary evidence. Use the Killer-Skills review above as the primary layer for fit, risk, and installation decisions.

After The Review

Decide The Next Action Before You Keep Reading Repository Material

Killer-Skills should not stop at opening repository instructions. It should help you decide whether to install this skill, when to cross-check against trusted collections, and when to move into workflow rollout.

Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is feed-datasource-expert?

Perfect for Frontend Agents needing advanced paginated list/feed widget capabilities with ValueNotifiers and Commands. Expert guidance on implementing paginated feeds and infinite scroll in Flutter using FeedDataSource and PagedFeedDataSource patterns. Covers base feed data source, cursor-based pagination, auto-pagina

How do I install feed-datasource-expert?

Run the command: npx killer-skills add flutter-it/watch_it/feed-datasource-expert. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for feed-datasource-expert?

Key use cases include: Implementing infinite scroll for dynamic content feeds, Building paginated lists with auto-pagination triggers, Managing entity lifecycles with proxy patterns for data-intensive applications.

Which IDEs are compatible with feed-datasource-expert?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for feed-datasource-expert?

Requires integration with ValueNotifiers and Commands. Auto-pagination triggers at items.length - 3, not at the last item. Proxies must be released after replacing with new ones during refresh.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add flutter-it/watch_it/feed-datasource-expert. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use feed-datasource-expert immediately in the current project.

! Reference-Only Mode

This page remains useful for installation and reference, but Killer-Skills no longer treats it as a primary indexable landing page. Read the review above before relying on the upstream repository instructions.

Upstream Repository Material

The section below is imported from the upstream repository and should be treated as secondary evidence. Use the Killer-Skills review above as the primary layer for fit, risk, and installation decisions.

Upstream Source

feed-datasource-expert

Install feed-datasource-expert, an AI agent skill for AI agent workflows and automation. Review the use cases, limitations, and setup path before rollout.

SKILL.md
Readonly
Upstream Repository Material
The section below is imported from the upstream repository and should be treated as secondary evidence. Use the Killer-Skills review above as the primary layer for fit, risk, and installation decisions.
Supporting Evidence

Feed DataSource Expert - Paged Lists & Infinite Scroll

What: Pattern for paginated, reactive list/feed widgets using ValueNotifiers and Commands. Integrates with proxy pattern for entity lifecycle management.

CRITICAL RULES

  • Auto-pagination triggers at items.length - 3 (not at the last item)
  • updateDataCommand for initial/refresh loads, requestNextPageCommand for pagination - separate commands
  • When refreshing with proxies: release OLD proxies AFTER replacing with new ones (delay release for animations)
  • itemCount is a ValueNotifier - watch it to rebuild the list widget
  • Feed data sources are typically created with createOnce in widgets, NOT registered in get_it
  • getItemAtIndex(index) both returns the item AND triggers auto-pagination

Base FeedDataSource

Non-paged feed for finite data sets:

dart
1abstract class FeedDataSource<TItem> { 2 FeedDataSource({List<TItem>? initialItems}) 3 : items = initialItems ?? []; 4 5 final List<TItem> items; 6 final _itemCount = CustomValueNotifier<int>(0); 7 ValueListenable<int> get itemCount => _itemCount; 8 bool updateWasCalled = false; 9 10 late final updateDataCommand = Command.createAsyncNoParamNoResult( 11 () async { 12 await updateFeedData(); 13 updateWasCalled = true; 14 refreshItemCount(); 15 }, 16 errorFilter: const LocalOnlyErrorFilter(), 17 ); 18 19 ValueListenable<bool> get isFetchingNextPage => updateDataCommand.isRunning; 20 ValueListenable<CommandError?> get commandErrors => updateDataCommand.errors; 21 22 /// Subclasses implement - fetch data and populate items list 23 Future<void> updateFeedData(); 24 25 /// Subclasses implement - compare items for deduplication 26 bool itemsAreEqual(TItem item1, TItem item2); 27 28 TItem getItemAtIndex(int index) { 29 assert(index >= 0 && index < items.length); 30 return items[index]; 31 } 32 33 void refreshItemCount() { 34 _itemCount.value = items.length; 35 } 36 37 void addItemAtStart(TItem item) { 38 items.insert(0, item); 39 refreshItemCount(); 40 } 41 42 void removeObject(TItem itemToRemove) { 43 items.removeWhere((item) => itemsAreEqual(item, itemToRemove)); 44 refreshItemCount(); 45 } 46 47 void reset() { 48 items.clear(); 49 updateWasCalled = false; 50 refreshItemCount(); 51 } 52 53 void dispose() { 54 _itemCount.dispose(); 55 } 56}

PagedFeedDataSource

Extends FeedDataSource with cursor-based pagination:

dart
1abstract class PagedFeedDataSource<TItem> extends FeedDataSource<TItem> { 2 String? nextPageUrl; 3 bool? datasetExpired; 4 5 bool get hasNextPage => nextPageUrl != null && datasetExpired != true; 6 7 late final requestNextPageCommand = Command.createAsyncNoParamNoResult( 8 () async { 9 await requestNextPage(); 10 refreshItemCount(); 11 }, 12 errorFilter: const LocalOnlyErrorFilter(), 13 ); 14 15 /// Subclasses implement - fetch next page and append to items 16 Future<void> requestNextPage(); 17 18 /// Call after parsing API response to store next page URL 19 void extractNextPageParams(String? url) { 20 nextPageUrl = url; 21 } 22 23 /// Auto-pagination: triggers when scrolling near the end 24 @override 25 TItem getItemAtIndex(int index) { 26 if (index >= items.length - 3 && 27 commandErrors.value == null && 28 hasNextPage && 29 !requestNextPageCommand.isRunning.value) { 30 requestNextPageCommand.run(); 31 } 32 return super.getItemAtIndex(index); 33 } 34 35 // Merged loading/error state from both commands 36 late final ValueNotifier<bool> _isFetchingNextPage = ValueNotifier(false); 37 @override 38 ValueListenable<bool> get isFetchingNextPage => _isFetchingNextPage; 39 40 // Listen to both commands and merge their isRunning states 41 // _isFetchingNextPage.value = updateDataCommand.isRunning.value || 42 // requestNextPageCommand.isRunning.value; 43 44 @override 45 void reset() { 46 nextPageUrl = null; 47 datasetExpired = null; 48 super.reset(); 49 } 50}

Concrete Implementation with Proxies

dart
1class PostsFeedSource extends PagedFeedDataSource<PostProxy> { 2 PostsFeedSource(this.feedType); 3 final PostFeedType feedType; 4 5 @override 6 bool itemsAreEqual(PostProxy a, PostProxy b) => a.id == b.id; 7 8 @override 9 Future<void> updateFeedData() async { 10 final api = PostApi(di<ApiClient>()); 11 final response = await api.getPosts(type: feedType); 12 if (response == null) return; 13 14 // Release old proxies (delay for exit animations) 15 final oldItems = List<PostProxy>.from(items); 16 items.clear(); 17 18 // Create new proxies via manager (increments ref count) 19 final proxies = di<PostsManager>().createProxies(response.data); 20 items.addAll(proxies); 21 extractNextPageParams(response.links?.next); 22 23 // Release old proxies after animations complete 24 Future.delayed(const Duration(milliseconds: 1000), () { 25 di<PostsManager>().releaseProxies(oldItems); 26 }); 27 } 28 29 @override 30 Future<void> requestNextPage() async { 31 if (nextPageUrl == null) return; 32 final response = await callNextPageWithUrl<PostListResponse>(nextPageUrl!); 33 if (response == null) return; 34 35 final proxies = di<PostsManager>().createProxies(response.data); 36 items.addAll(proxies); 37 extractNextPageParams(response.links?.next); 38 } 39 40 // Override to manage reference counting on individual operations 41 @override 42 void addItemAtStart(PostProxy item) { 43 item.incrementReferenceCount(); 44 super.addItemAtStart(item); 45 } 46 47 @override 48 void removeObject(PostProxy item) { 49 super.removeObject(item); 50 di<PostsManager>().releaseProxy(item); 51 } 52}

Feed Widget

dart
1class FeedView<TItem> extends WatchingWidget { 2 const FeedView({ 3 required this.feedSource, 4 required this.itemBuilder, 5 this.emptyListWidget, 6 }); 7 8 final FeedDataSource<TItem> feedSource; 9 final Widget Function(BuildContext, TItem) itemBuilder; 10 final Widget? emptyListWidget; 11 12 @override 13 Widget build(BuildContext context) { 14 final itemCount = watch(feedSource.itemCount).value; 15 final isFetching = watch(feedSource.isFetchingNextPage).value; 16 17 // Trigger initial load 18 callOnce((_) => feedSource.updateDataCommand.run()); 19 20 // Error handler 21 registerHandler( 22 target: feedSource.commandErrors, 23 handler: (context, error, _) { 24 showErrorSnackbar(context, error.error); 25 }, 26 ); 27 28 // Error state with retry 29 if (feedSource.commandErrors.value != null && itemCount == 0) { 30 return ErrorWidget( 31 onRetry: () => feedSource.updateDataCommand.run(), 32 ); 33 } 34 35 // Initial loading 36 if (!feedSource.updateWasCalled && isFetching) { 37 return Center(child: CircularProgressIndicator()); 38 } 39 40 // Empty state 41 if (itemCount == 0 && feedSource.updateWasCalled) { 42 return emptyListWidget ?? Text('No items'); 43 } 44 45 // List with pull-to-refresh 46 return RefreshIndicator( 47 onRefresh: () => feedSource.updateDataCommand.runAsync(), 48 child: ListView.builder( 49 itemCount: itemCount + (isFetching ? 1 : 0), 50 itemBuilder: (context, index) { 51 if (index >= itemCount) { 52 return Center(child: CircularProgressIndicator()); 53 } 54 // getItemAtIndex auto-triggers pagination near end 55 final item = feedSource.getItemAtIndex(index); 56 return itemBuilder(context, item); 57 }, 58 ), 59 ); 60 } 61}

Creation Pattern

dart
1// Create with createOnce in the widget that owns the feed 2class PostsFeedPage extends WatchingWidget { 3 @override 4 Widget build(BuildContext context) { 5 final feedSource = createOnce( 6 () => PostsFeedSource(PostFeedType.latest), 7 dispose: (source) => source.dispose(), 8 ); 9 10 return FeedView<PostProxy>( 11 feedSource: feedSource, 12 itemBuilder: (context, post) => PostCard(post: post), 13 emptyListWidget: Text('No posts yet'), 14 ); 15 } 16}

Filtered Feeds

Same data, different views via filter functions:

dart
1class ChatsListSource extends PagedFeedDataSource<ChatProxy> { 2 ChatFilterType _filter = ChatFilterType.ALL; 3 String _query = ''; 4 5 void setTypeFilter(ChatFilterType filter) { 6 _filter = filter; 7 updateDataCommand.run(); // Re-fetch with new filter 8 } 9 10 void setSearchQuery(String query) { 11 _query = query; 12 updateDataCommand.run(); 13 } 14}

Event Bus Integration

Feeds can react to events from other parts of the app:

dart
1// In FeedDataSource constructor 2di<EventBus>().on<FeedEvent>().listen((event) { 3 if (event.feedsToApply.contains(feedId)) { 4 switch (event.action) { 5 case FeedEventActions.update: 6 updateDataCommand.run(); 7 case FeedEventActions.addItem: 8 addItemAtStart(event.data as TItem); 9 case FeedEventActions.removeItem: 10 removeObject(event.data as TItem); 11 } 12 } 13}); 14 15// Trigger from anywhere in the app 16di<EventBus>().fire(FeedEvent( 17 action: FeedEventActions.addItem, 18 data: newPostProxy, 19 feedsToApply: [FeedIds.latestPostsFeed, FeedIds.followingPostsFeed], 20));

Anti-Patterns

dart
1// ❌ Releasing proxies immediately on refresh (breaks exit animations) 2items.clear(); 3di<Manager>().releaseProxies(oldItems); // Widgets still animating! 4items.addAll(newProxies); 5 6// ✅ Delay release for animations 7final oldItems = List.from(items); 8items.clear(); 9items.addAll(newProxies); 10Future.delayed(Duration(milliseconds: 1000), () { 11 di<Manager>().releaseProxies(oldItems); 12}); 13 14// ❌ Registering feed in get_it as singleton 15di.registerSingleton<PostsFeed>(PostsFeedSource()); 16// ✅ Create with createOnce in the widget that owns it 17final feed = createOnce(() => PostsFeedSource()); 18 19// ❌ Manually checking scroll position for pagination 20scrollController.addListener(() { 21 if (scrollController.position.pixels >= ...) loadMore(); 22}); 23// ✅ Auto-pagination via getItemAtIndex triggers at length - 3 24 25// ❌ Single command for both initial load and pagination 26// ✅ Separate commands: updateDataCommand + requestNextPageCommand 27// Allows independent loading/error states and restrictions

Related Skills

Looking for an alternative to feed-datasource-expert or another community skill for your workflow? Explore these related open-source skills.

View All

openclaw-release-maintainer

Logo of openclaw
openclaw

Your own personal AI assistant. Any OS. Any Platform. The lobster way. 🦞

333.8k
0
AI

widget-generator

Logo of f
f

Generate customizable widget plugins for the prompts.chat feed system

149.6k
0
AI

flags

Logo of vercel
vercel

The React Framework

138.4k
0
Browser

pr-review

Logo of pytorch
pytorch

Tensors and Dynamic neural networks in Python with strong GPU acceleration

98.6k
0
Developer