Back to skills
SkillHub ClubAnalyze Data & AIFull StackFrontendData / AI

rdc-manager

Implement @data-client/react Managers for global side effects - websocket, SSE, polling, subscriptions, logging, middleware, Controller actions, redux pattern

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
2,027
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
A88.0

Install command

npx @skill-hub/cli install reactive-data-client-rdc-manager

Repository

reactive/data-client

Skill path: .cursor/skills/rdc-manager

Implement @data-client/react Managers for global side effects - websocket, SSE, polling, subscriptions, logging, middleware, Controller actions, redux pattern

Open repository

Best for

Primary workflow: Analyze Data & AI.

Technical facets: Full Stack, Frontend, Data / AI.

Target audience: everyone.

License: Apache 2.0.

Original source

Catalog source: SkillHub Club.

Repository owner: reactive.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install rdc-manager into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/reactive/data-client before adding rdc-manager to shared team environments
  • Use rdc-manager for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: rdc-manager
description: Implement @data-client/react Managers for global side effects - websocket, SSE, polling, subscriptions, logging, middleware, Controller actions, redux pattern
license: Apache 2.0
---
# Guide: Using `@data-client/react` Managers for global side effects

[Managers](https://dataclient.io/docs/api/Manager) are singletons that handle global side-effects. Kind of like useEffect() for the central data store.
They interface with the store using [Controller](https://dataclient.io/docs/api/Controller), and [redux middleware](https://redux.js.org/tutorials/fundamentals/part-4-store#middleware) is run in response to [actions](https://dataclient.io/docs/api/Actions).

## References

For detailed API documentation, see the [references](references/) directory:

- [Manager](references/Manager.md) - Manager interface and lifecycle
- [Actions](references/Actions.md) - Action types and payloads
- [Controller](references/Controller.md) - Imperative actions
- [managers](references/managers.md) - Managers concept guide

Always use `actionTypes` when comparing action.type. Refer to [Actions](references/Actions.md) for list of actions and their payloads.

## Dispatching actions

[Controller](https://dataclient.io/docs/api/Controller) has dispatchers:
ctrl.fetch(), ctrl.fetchIfStale(), ctrl.expireAll(), ctrl.invalidate(), ctrl.invalidateAll(), ctrl.setResponse(), ctrl.set().

```ts
import type { Manager, Middleware } from '@data-client/core';
import CurrentTime from './CurrentTime';

export default class TimeManager implements Manager {
  protected declare intervalID?: ReturnType<typeof setInterval>;

  middleware: Middleware = controller => {
    this.intervalID = setInterval(() => {
      controller.set(CurrentTime, { id: 1 }, { id: 1, time: Date.now() });
    }, 1000);

    return next => async action => next(action);
  };

  cleanup() {
    clearInterval(this.intervalID);
  }
}
```

## Reading and Consuming Actions

[Controller](https://dataclient.io/docs/api/Controller) has data accessors:
controller.getResponse(), controller.getState(), controller.get(), controller.getError()

```ts
import type { Manager, Middleware } from '@data-client/react';
import { actionTypes } from '@data-client/react';

export default class LoggingManager implements Manager {
  middleware: Middleware = controller => next => async action => {
    switch (action.type) {
      case actionTypes.SET_RESPONSE:
        if (action.endpoint.sideEffect) {
          console.info(
            `${action.endpoint.name} ${JSON.stringify(action.response)}`,
          );
          // wait for state update to be committed to React
          await next(action);
          // get the data from the store, which may be merged with existing state
          const { data } = controller.getResponse(
            action.endpoint,
            ...action.args,
            controller.getState(),
          );
          console.info(`${action.endpoint.name} ${JSON.stringify(data)}`);
          return;
        }
      // actions must be explicitly passed to next middleware
      default:
        return next(action);
    }
  };

  cleanup() {}
}
```

Always use `actionTypes` members to check action.type.
`actionTypes` has: FETCH, SET, SET_RESPONSE, RESET, SUBSCRIBE, UNSUBSCRIBE, INVALIDATE, INVALIDATEALL, EXPIREALL

[actions](https://dataclient.io/docs/api/Actions) docs details the action types and their payloads.

## Consuming actions

```ts
import type { Manager, Middleware, EntityInterface } from '@data-client/react';
import { actionTypes } from '@data-client/react';
import isEntity from './isEntity';

export default class CustomSubsManager implements Manager {
  protected declare entities: Record<string, EntityInterface>;

  middleware: Middleware = controller => next => async action => {
    switch (action.type) {
      case actionTypes.SUBSCRIBE:
      case actionTypes.UNSUBSCRIBE:
        const { schema } = action.endpoint;
        // only process registered entities
        if (schema && isEntity(schema) && schema.key in this.entities) {
          if (action.type === actionTypes.SUBSCRIBE) {
            this.subscribe(schema.key, action.args[0]?.product_id);
          } else {
            this.unsubscribe(schema.key, action.args[0]?.product_id);
          }

          // consume subscription to prevent it from being processed by other managers
          return Promise.resolve();
        }
      default:
        return next(action);
    }
  };

  cleanup() {}

  subscribe(channel: string, product_id: string) {}
  unsubscribe(channel: string, product_id: string) {}
}
```

## Usage

```tsx
import { DataProvider, getDefaultManagers } from '@data-client/react';
import ReactDOM from 'react-dom';

const managers = [...getDefaultManagers(), new MyManager()];

ReactDOM.createRoot(document.body).render(
  <DataProvider managers={managers}>
    <App />
  </DataProvider>,
);
```


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### references/Manager.md

```markdown
../../../../docs/core/api/Manager.md
```

### references/Actions.md

```markdown
../../../../docs/core/api/Actions.md
```

### references/Controller.md

```markdown
../../../../docs/core/api/Controller.md
```

### references/managers.md

```markdown
../../../../docs/core/concepts/managers.md
```

rdc-manager | SkillHub