feed-datasource-expert — feed-datasource-expert install and configuration feed-datasource-expert, watch_it, community, feed-datasource-expert install and configuration, ide skills, Claude Code, Cursor, Windsurf

v1.0
GitHub

About this Skill

Perfect for Frontend Agents needing advanced paginated list/feed widget capabilities with ValueNotifiers and Commands. feed-datasource-expert is a pattern for paginated, reactive list/feed widgets using ValueNotifiers and Commands, designed for efficient data handling and entity lifecycle management.

Features

Auto-pagination triggers at items.length - 3 for efficient data loading
Utilizes updateDataCommand for initial and refresh loads
Employs requestNextPageCommand for pagination with separate commands
Integrates with proxy pattern for entity lifecycle management
Supports release of old proxies after replacing with new ones for refreshing data

# Core Topics

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

Agent Capability Analysis

The feed-datasource-expert skill by flutter-it is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance. Optimized for feed-datasource-expert install and configuration.

Ideal Agent Persona

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

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.

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
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

feed-datasource-expert

Install feed-datasource-expert, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command setup.

SKILL.md
Readonly

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

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. feed-datasource-expert is a pattern for paginated, reactive list/feed widgets using ValueNotifiers and Commands, designed for efficient data handling and entity lifecycle management.

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.

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

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI