Skip to content

feat(router): Add useHistoryState hook for type-safe history state management #3967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 33 commits into
base: main
Choose a base branch
from

Conversation

naoya7076
Copy link

@naoya7076 naoya7076 commented Apr 9, 2025

Overview

This PR introduces the new useHistoryState hook and related functionality to enable type-safe history state management in TanStack Router.

Background

In the current implementation of TanStack Router, to pass type-safe state (History State) between routes that isn't part of the path or params, we need to define types globally. This leads to two main issues:

  1. Type pollution - types appear in places where they aren't needed
  2. Interface bloat - as more states are added, the global interface grows excessively

For example:

declare module '@tanstack/react-router' {
  interface HistoryState {
    user?: MyUserType;
    project?: MyProjectType;
  }
}

#284
When migrating from react-router to TanStack Router, developers want to be able to handle state in a type-safe manner, similar to how they could with react-router:

const history = useHistory();
history.replace({ pathname: '/', state: { name: 'Lily' }});
...
const location = useLocation();
// do something with location.state...

This PR addresses these issues by adding route-specific, type-safe history state management.

Changes

  • Added useHistoryState hook export in the main package index
  • Extended the FileRoute class to support state validation with TStateValidator generic parameter
  • Created a full example in examples/react/basic-history-state demonstrating usage patterns
  • The example shows how to:
    • Define state schemas using Zod
    • Pass state during navigation with Link and navigate

Key features of useHistoryState

  • Type-safe access to history state passed during navigation
  • Support for default values and optional properties
  • Ability to select specific state properties
  • Non-strict mode for accessing raw state object

Example usage

Users can define state validation on routes:

validateState: (input) =>
  z.object({
    color: z.enum(['white', 'red', 'green', 'blue']).default('white'),
    visited: z.boolean().default(false),
    message: z.string().optional(),
  }).parse(input),

Then use it in components:

// From route directly
const state = postRoute.useHistoryState()

// With select to extract specific values
const color = useHistoryState({
  from: '/posts/post',
  select: (state) => state.color
})

Need help

Unit test fix

  • packages/react-router/tests/route.test-d.tsx:L1234-L1236
  • packages/solid-router/tests/route.test-d.tsx:L1289-L1291
    There are two failing tests that I couldn't fix on my own. Any advice would be appreciated!

This commit introduces a new `validateState` function to handle state validation within the router. It supports various validation methods, including standard validation and parsing, and integrates with route options to validate state during routing.
This commit introduces the TStateValidator type across various routing components, enhancing the validation capabilities for state management. The changes include updates to the createFileRoute and Route classes, as well as adjustments in related files to support the new state validation feature.
This commit introduces the `useHistoryState` hook and related types across various routing components, improving state management capabilities. Updates include modifications to the Route and createRoute functions to support the new state handling feature.
This commit introduces a new section in the BaseTanStackRouterDevtoolsPanel to display state parameters when available.
This commit introduces the `useHistoryState` hook along with its associated types, enhancing the state management capabilities within the router. The new implementation allows for more flexible state handling and selection options, improving overall functionality.
This commit introduces new TypeScript types related to the `useHistoryState` hook, improving type safety and flexibility in state management within the router. The new types facilitate better state selection and handling options, enhancing the overall functionality of the routing system.
…roved state selection

This commit refactoring the state selection logic to utilize `useRouterState`.
…resolution

This commit modifies the `ResolveUseHistoryState` and ` UseHistoryStateResult` types
…ryState

This commit updates the `useHistoryState` hook to utilize `useLocation` for state management instead of `useRouterState`, improving the clarity and efficiency of state selection logic.
@github-actions github-actions bot added the documentation Everything documentation related label Apr 26, 2025
@naoya7076 naoya7076 changed the title feat(react-router): Add useHistoryState hook for type-safe history state management feat(router): Add useHistoryState hook for type-safe history state management Apr 28, 2025
naoya7076 and others added 2 commits April 28, 2025 23:00
Co-authored-by: Ahmed Abdelbaset <A7med3bdulBaset@gmail.com>
Co-authored-by: Ahmed Abdelbaset <A7med3bdulBaset@gmail.com>
@naoya7076 naoya7076 marked this pull request as ready for review April 28, 2025 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants