getState - greydragon888/real-router GitHub Wiki
- What it does: Returns the current router state. The state contains route name, parameters, and path.
-
When to use:
- To get information about the current route
- To check current route parameters
- For conditional logic based on current state
- For integration with UI frameworks
router.getState<P extends Params = Params>(): State<P> | undefinedtype State<P extends Params = Params> = {
name: string;
params: P;
path: string;
};
type Params = Record<string, unknown>;// Basic usage
const state = router.getState();
if (state) {
console.log(state.name); // 'users.view'
console.log(state.params); // { id: '123' }
console.log(state.path); // '/users/123'
}
// With typed parameters
interface UserParams {
id: string;
tab?: string;
}
const state = router.getState<UserParams>();
if (state) {
console.log(state.params.id); // Typed as string
}
// Check state before navigation
const currentState = router.getState();
if (currentState?.name !== 'login') {
router.navigate('login');
}
// React integration
function CurrentRoute() {
const [state, setState] = useState(router.getState());
useEffect(() => {
return router.subscribe((routeState) => {
setState(routeState.route);
});
}, []);
return state ? <div>{state.name}</div> : null;
}The method takes no parameters.
| Parameter | Default | Description |
|---|---|---|
P |
Params |
Route parameters type |
-
Type:
State<P> | undefined -
undefined: If router is not started or was stopped -
State: If router is started and has current state
| Field | Type | Description |
|---|---|---|
name |
string |
Route name (dot-separated) |
params |
P |
Route parameters |
path |
string |
URL path |
- Returned state is frozen (deeply frozen) — modification attempts will throw error in strict mode
- This is a cached value — repeated calls return the same object without overhead
- State is updated only as a result of successful navigation or
navigateToNotFound()
The method has no side effects — it's a pure getter function.
The method does not throw errors.
| Method | When to use |
|---|---|
getPreviousState() |
Getting previous state |
isActive() |
Checking router state |
start() |
Starting the router |
stop() |
Stopping the router |
-
Non-started router: Returns
undefined - Started router: Returns current state
-
After stopping: Returns
undefined
import { getPluginApi } from "@real-router/core/api";
const pluginApi = getPluginApi(router);
// Returns undefined when router is not started
router.stop();
expect(router.getState()).toBe(undefined);
// Returns set state
const state = pluginApi.makeState("home", { id: 1 }, "/home");
router.setState(state);
expect(router.getState()).toStrictEqual(state);// 1. Before start
const router = createRouter(routes);
expect(router.getState()).toBe(undefined);
// 2. After start
await router.start("/home");
expect(router.getState()).toBeDefined();
expect(router.getState()?.name).toBe("home");
// 3. After navigation
await router.navigate("users");
expect(router.getState()?.name).toBe("users");
// 4. After stop
router.stop();
expect(router.getState()).toBe(undefined);// State is frozen
const state = router.getState();
expect(Object.isFrozen(state)).toBe(true);
// Modification attempt throws error (strict mode)
expect(() => {
state!.name = "modified";
}).toThrowError();// Repeated calls return same object
const state1 = router.getState();
const state2 = router.getState();
expect(state1).toBe(state2); // Referential equality-
Non-started router:
undefined -
After
stop():undefined -
After
setState(undefined):undefined - With generic types: Returns typed state
- Returned state is immutable (deeply frozen)
- Repeated calls return same object (caching)
-
undefinedwhen router is not active - Typing through generic
P - Has no side effects
| router5 (master) | Real Router (current) | |
|---|---|---|
| Signature | () => State | null |
<P>() => State<P> | undefined |
| Return when absent | null |
undefined |
| Immutability | No | Deeply frozen |
| Caching | No (direct access) | Cached frozen state |
| TypeScript generics | No |
P parameter type |
router5 (old):
router.getState = () => routerState; // routerState: State | null
// Check for null
const state = router.getState();
if (state === null) {
console.log("Router not started");
}Real Router (new):
router.getState = (): State<P> | undefined => frozenState;
// Check for undefined
const state = router.getState();
if (state === undefined) {
console.log("Router not started");
}Impact: Code explicitly checking === null will no longer correctly detect missing state. However checks like if (!state) or if (state) will continue to work.
router5 (old):
const state = router.getState();
state.params.newParam = "value"; // OK — can modify
state.name = "modified"; // OK — can modifyReal Router (new):
const state = router.getState();
state.params.newParam = "value"; // TypeError in strict mode
state.name = "modified"; // TypeError in strict modeImpact: Code that modifies returned state directly will get an error. This is an anti-pattern violating encapsulation. Create new object via spread or makeState().
- Replace
=== nullchecks with=== undefinedor use!state - Ensure code doesn't modify returned state directly
- Use spread
{ ...state, ... }to create modified copy
null → undefined Check
// ❌ Old code
if (router.getState() === null) {
console.log("Not started");
}
// ✅ New code — explicit check
if (router.getState() === undefined) {
console.log("Not started");
}
// ✅ Or — universal check (works in both cases)
if (!router.getState()) {
console.log("Not started");
}State Modification → Creating Copy
import { getPluginApi } from "@real-router/core/api";
const pluginApi = getPluginApi(router);
// ❌ Old code — direct modification
const state = router.getState();
state.params.newParam = "value";
// ✅ New code — create copy via spread
const state = router.getState();
const modified = {
...state,
params: { ...state.params, newParam: "value" },
};
// ✅ Or use makeState
const modified = pluginApi.makeState(
state.name,
{ ...state.params, newParam: "value" },
state.path,
);TypeScript — Using Generic Types
// ❌ Old code — without typing
const state = router.getState();
const id = state?.params.id as string; // Type assertion
// ✅ New code — with typing
interface MyParams {
id: string;
filter?: string;
}
const state = router.getState<MyParams>();
const id = state?.params.id; // Typed as string (P = MyParams)