effector / effector/router

Standalone trackQuery / syncQuery operators, deprecate router.trackQuery method

Open
#66 0 comments 0 reactions 0 assignees View on GitHub
atomic-router feature parity enhancement RFC scope:core
Dominant language
TypeScript
Stars
8
Forks
2
Avg merge
13h 44m
Merged PRs (30d)
1

Description

### Problem

`trackQuery` is a method on `Router`/`RouterControls`, which is invisible to `effector/babel-plugin` / SWC plugin factories (`factories: ['@effector/router']`) — units created inside get no stable SIDs for SSR/devtools. Additionally, there is no primitive for two-way store↔query binding: atomic-router's `querySync` use case ("keep N stores in sync with N query keys, with cleanup") is not covered by the zod-based `trackQuery`, making migration painful.

### Proposed solution

Two top-level operators, single config field `router` accepting either a `Router` or `RouterControls`:

```ts
import { trackQuery, syncQuery } from '@effector/router';

const tracker = trackQuery({
router, // Router | RouterControls
parameters: z.object({ modal: z.literal('settings') }),
forRoutes: [settingsPage], // any routes, incl. virtual/group
check, // Event, optional
});

syncQuery({
router,
source: { page: $page, sort: $sort }, // query key -> Store
forRoutes: [listPage], // optional
clock, // Unit, optional; when to write to URL, default: source change
cleanup: { empty: true, irrelevant: false, preserve: [] }, // documented default
});
```

Key design change: `forRoutes` is implemented via `or(...forRoutes.map((r) => r.$isOpened))` (patronum) instead of `$activeRoutes`. This removes the Router/Controls asymmetry (no overloads needed), lets `forRoutes` accept pathless/virtual/group/chained routes and routes from nested routers, and is semantically more correct — a tracker should not "enter" while `beforeOpen` guards are pending or a chain was cancelled. `router.trackQuery`/`controls.trackQuery` methods stay as deprecated delegates in the same minor and are removed in the next major (user base is still tiny). Behavioral note for the changelog: with `forRoutes` the filter shifts from "path matched" to "route actually opened".

Related: #40 (read/write mapping fits `syncQuery` design), #35.

### Alternatives considered

Adding `$activeRoutes` to `RouterControls` for symmetry — rejected: controls are deliberately route-agnostic and shared between routers; aggregating routes there couples them to whoever happens to attach.

### Package

`@effector/router` (core)

Contributor guide

Open the contributing guide

Research direction

Start by reading the existing Router and RouterControls trackQuery methods in the @effector/router core package, then review related issues #40 and #35 for the mapping and migration context. Done means the standalone trackQuery and syncQuery operators, Router/RouterControls delegates, route-opening behavior, cleanup defaults, and deprecation path are covered consistently.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.