Skip to content
asyncredux-selectors logo

Asyncredux Selectors

asyncredux-selectors

Create and cache selectors for efficient state access. Covers writing selector functions, caching with `cache1` and `cache2`, the reselect pattern, and avoiding repeated computations in widgets.

SKILL.md

Full skill instructions

What Are Selectors?

Selectors are functions that extract specific data from the Redux store state. They provide three key benefits:

  1. Compute derived data - Transform or filter state into the format your widget needs
  2. Abstract state structure - Components don't depend on how the state is organized
  3. Enable caching (memoization) - Avoid unnecessary recalculations

The Problem: Repeated Computations

When displaying filtered or computed data, without selectors you might write:

// INEFFICIENT - filters the entire list on every access
state.users.where((user) => user.name.startsWith("A")).toList()[index].name;

This filtering operation runs every time the widget rebuilds, even when the data hasn't changed.

Basic Selector Functions

Create a selector function that performs the computation once:

List<User> selectUsersStartingWith(AppState state, String text) {
  return state.users.where((user) => user.name.startsWith(text)).toList();
}

Cached Selectors (Reselectors)

For expensive computations, wrap your selector with a cache function. AsyncRedux provides built-in caching utilities.

Basic Caching Example

List<User> selectUsersStartingWith(AppState state, {required String text}) =>
    _selectUsersStartingWith(state)(text);

static final _selectUsersStartingWith = cache1state_1param(
  (AppState state) => (String text) =>
      state.users.where((user) => user.name.startsWith(text)).toList()
);

Optimized Caching (State Subset)

For better performance, only depend on the specific state subset that matters:

List<User> selectUsersStartingWith(AppState state, {required String text}) =>
    _selectUsersStartingWith(state.users)(text);

static final _selectUsersStartingWith = cache1state_1param(
  (List<User> users) => (String text) =>
      users.where((user) => user.name.startsWith(text)).toList()
);

This version only recalculates when state.users changes, not when any part of state changes.

Available Cache Functions

AsyncRedux provides these caching functions:

FunctionStatesParametersUse Case
cache1state10Simple computed value from one state
cache1state_1param11Filtered/​computed value with one param
cache1state_2params12Computation with two parameters
cache1state_0params_x1ManyVariable number of parameters
cache2states20Combines two state portions
cache2states_1param21Combines two states with one param
cache2states_2params22Combines two states with two params
cache2states_0params_x2ManyTwo states, variable params
cache3states30Combines three state portions
cache3states_0params_x3ManyThree states, variable params

The naming convention: cache[N]state[s]_[M]param[s] where N = number of states, M = number of parameters.

Cache Characteristics

  • Multiple cached results - Maintains separate caches for different parameter combinations
  • Weak-map storage - Automatically discards cached data when states change or fall out of use
  • Memory efficient - Won't hold obsolete information

Action Selectors

Create selectors that actions can use via a dedicated class:

class ActionSelect {
  final AppState state;
  ActionSelect(this.state);

  List<Item> get items => state.items;
  Item get selectedItem => state.selectedItem;

  Item? findById(int id) =>
      state.items.firstWhereOrNull((item) => item.id == id);

  Item? searchByText(String text) =>
      state.items.firstWhereOrNull((item) => item.text.contains(text));

  int get selectedIndex => state.items.indexOf(state.selectedItem);
}

Add a getter in your base action:

abstract class AppAction extends ReduxAction<AppState> {
  ActionSelect get select => ActionSelect(state);
}

Usage in actions:

class LoadItemAction extends AppAction {
  final int itemId;
  LoadItemAction(this.itemId);

  @override
  AppState? reduce() {
    var item = select.findById(itemId);
    if (item == null) return null;
    return state.copy(selectedItem: item);
  }
}

Widget Selectors

Create a WidgetSelect class for organized widget-level selectors:

class WidgetSelect {
  final BuildContext context;
  WidgetSelect(this.context);

  List<Item> get items => context.select((st) => st.items);
  Item get selectedItem => context.select((st) => st.selectedItem);

  Item? findById(int id) =>
      context.select((st) => st.items.firstWhereOrNull((item) => item.id == id));

  Item? searchByText(String text) =>
      context.select((st) => st.items.firstWhereOrNull((item) => item.text.contains(text)));

  int get selectedIndex =>
      context.select((st) => st.items.indexOf(st.selectedItem));
}

Add to your BuildContext extension:

extension BuildContextExtension on BuildContext {
  AppState get state => getState<AppState>();
  R select<R>(R Function(AppState state) selector) => getSelect<AppState, R>(selector);
  WidgetSelect get selector => WidgetSelect(this);
}

Usage in widgets:

Widget build(BuildContext context) {
  final item = context.selector.findById(42);
  return Text(item?.name ?? 'Not found');
}

Reusing Action Selectors in Widgets

Widget selectors can leverage action selectors to avoid duplication:

class WidgetSelect {
  final BuildContext context;
  WidgetSelect(this.context);

  Item? findById(int id) =>
      context.select((st) => ActionSelect(st).findById(id));

  Item? searchByText(String text) =>
      context.select((st) => ActionSelect(st).searchByText(text));
}

Important Guidelines

Avoid context.state Inside Selectors

Never use context.state inside selector functions - this defeats selective rebuilding:

// WRONG - rebuilds on any state change
var items = context.select((state) => context.state.items.where(...));

// CORRECT - only rebuilds when items change
var items = context.select((state) => state.items.where(...));

Never Nest context.select Calls

Nesting context.select causes errors:

// WRONG - will cause errors
var result = context.select((state) =>
  context.select((s) => s.items).where(...)  // Nested select!
);

// CORRECT
var items = context.select((state) => state.items);
var result = items.where(...).toList();

Comparison with External Reselect Package

AsyncRedux's built-in caching differs from the external reselect package:

FeatureAsyncReduxreselect
Results per selectorMultiple (different params)One only
Memory on state changeDiscards old cacheRetains indefinitely

Complete Example: Cached Filtered List

// Selector with caching
class UserSelectors {
  static List<User> usersStartingWith(AppState state, String prefix) =>
      _usersStartingWith(state.users)(prefix);

  static final _usersStartingWith = cache1state_1param(
    (List<User> users) => (String prefix) =>
        users.where((u) => u.name.startsWith(prefix)).toList()
  );

  static List<User> activeUsers(AppState state) =>
      _activeUsers(state.users);

  static final _activeUsers = cache1state(
    (List<User> users) => users.where((u) => u.isActive).toList()
  );
}

// Usage in widget
Widget build(BuildContext context) {
  var filtered = context.select(
    (state) => UserSelectors.usersStartingWith(state, 'A')
  );
  return ListView.builder(
    itemCount: filtered.length,
    itemBuilder: (_, i) => Text(filtered[i].name),
  );
}

References

URLs from the documentation:

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View