Package
@effector/router (core)
What happened?
When a route that has a beforeOpen handler is opened through the public open API (which is exactly what <Link> does under the hood), the beforeOpen effects run twice for a single navigation. During the extra pending window the route is briefly not $isOpened, which surfaces a spurious "404" flash before the page settles.
Expected: beforeOpen should run exactly once per navigation, and the route should not flash an unopened/404 state.
Sequence that causes the duplicate:
route.open() runs openFx (beforeOpen 1) → on openFx.done the router pushes the location → locationUpdated → openRoutesByPathFx re-triggers the route via navigated → navigatedFx (attach({ effect: openFx })) runs openFx again (beforeOpen 2).
This is inherited from the predecessor project — see the original report: movpushmov/argon-router#30
Reproduction
const beforeOpenFn = vi.fn();
const profile = createRoute({
path: '/profile',
beforeOpen: [createEffect(beforeOpenFn)],
});
const feed = createRoute({ path: '/' });
const router = createRouter({ routes: [feed, profile] });
const history = createMemoryHistory();
await allSettled(router.setHistory, { scope, params: historyAdapter(history) });
// `<Link to={routes.profile}>` navigation is `route.open()`.
await allSettled(profile.open, { scope, params: {} });
expect(beforeOpenFn).toBeCalledTimes(1); // fails: called 2 times
A failing reproduction test is added in packages/core/tests/issue-30-before-open-called-twice.test.ts.
Steps in the original app repro:
- Route with an async
beforeOpen effect on /profile.
- Click a
<Link> to that route.
- Observe the
beforeOpen effect logs twice and a 404 page flashes during the transition.
Environment
- @effector/router: 1.1.0
- effector: >=23
- node: 24.x
Package
@effector/router (core)
What happened?
When a route that has a
beforeOpenhandler is opened through the publicopenAPI (which is exactly what<Link>does under the hood), thebeforeOpeneffects run twice for a single navigation. During the extra pending window the route is briefly not$isOpened, which surfaces a spurious "404" flash before the page settles.Expected:
beforeOpenshould run exactly once per navigation, and the route should not flash an unopened/404 state.Sequence that causes the duplicate:
route.open()runsopenFx(beforeOpen 1) → onopenFx.donethe router pushes the location →locationUpdated→openRoutesByPathFxre-triggers the route vianavigated→navigatedFx(attach({ effect: openFx })) runsopenFxagain (beforeOpen 2).This is inherited from the predecessor project — see the original report: movpushmov/argon-router#30
Reproduction
A failing reproduction test is added in
packages/core/tests/issue-30-before-open-called-twice.test.ts.Steps in the original app repro:
beforeOpeneffect on/profile.<Link>to that route.beforeOpeneffect logs twice and a 404 page flashes during the transition.Environment