Skip to content
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

Route.to becomes undefined after a HMR save #1640

Open
vishal-tiwari opened this issue May 20, 2024 · 3 comments
Open

Route.to becomes undefined after a HMR save #1640

vishal-tiwari opened this issue May 20, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@vishal-tiwari
Copy link

Describe the bug

When making changes to the generateShareableHook function, the route created by createFileRoute starts returning undefined on the development server. This issue affects navigation and component rendering, causing the application to malfunction.

Steps to Reproduce:

  1. Set up the router in App.tsx as shown:
const router = createRouter({ routeTree });
declare module '@tanstack/react-router' {
  interface Register {
    router: typeof router;
  }
}

export default function App() {
  return (
    <RouterProvider router={router} />
  );
}
  1. Define the root route in __root.tsx:
export const Route = createRootRoute({
  component: MyAppLayout,
});
  1. Implement MyAppLayout:
import { AppLayout } from '@cloudscape-design/components';

export const useAppLayout = generateShareableHook<AppLayoutProps>({});

export default function myAppLayout(): ReactElement {
  const [settings] = useAppLayout();
  return (
    <AppLayout
      headerSelector={`#${SiteTopHeaderSelectorId}`}
      navigation={<SideNavigation />}
      content={<Outlet />}
      {...settings}
    />
  );
}

  1. Create the index route:
function Home(): ReactElement {
  console.log('rendering Home', route.to);
  const [s, setS] = useAppLayout();
  return (
    <>
      <Button
        onClick={() => {
          setS({ navigationHide: !s.navigationHide, toolsHide: !s.toolsHide });
        }}>
        Click me
      </Button>
      <h1>Hello /device-groups/</h1>
    </>
  );
}
export const Route = createFileRoute('/')({
  component: Home,
});

  1. Modify the generateShareableHook:
import { Dispatch, SetStateAction, useEffect, useState } from 'react';

type Listener<L> = Dispatch<SetStateAction<L>>;
// Define a type for the enhanced useShareableState hook
type UseShareableState<T> = {
  (newState?: T): [T, (newState: T) => void];
  getState: () => T;
  setState: (newState: T) => void;
};

// A function that generates a React Hook that has a common state/setState context for all React
// components that use it.
export default function generateShareableHook<T>(initialState: T): UseShareableState<T> {
  // Set the initial shared state of the hook.
  let internalState = initialState;

  // Create the list of listeners that will be called whenever the state changes.
  const listeners: Set<Listener<T>> = new Set();

  // Proxy function for React's own React.SetStateAction. This calls all components that are
  // currently listening to the generated hook's shared state.
  const setState = (newState: T) => {
    internalState = newState;
    listeners.forEach((listener) => listener(internalState));
  };

  // Function to get the current state
  const getState = () => internalState;

  // The React Hook that is returned, for use by any React component that consumes whatever module
  // generates the shared hook in the first place.
  function useShareableState(newState?: T): [T, typeof setState] {
    const [state, setStateListener] = useState<T>(internalState);

    // Push the new setState function into the list of listeners to call when the state changes.
    useEffect(() => {
      listeners.add(setStateListener);

      // If the component calling the hook has passed a new state, set it here.
      if (newState !== undefined) {
        setState(newState);
      }

      return () => {
        listeners.delete(setStateListener);
      };
    }, [newState]); // Only re-run the effect if `newState` changes

    return [state, setState];
  }

  useShareableState.getState = getState;
  useShareableState.setState = setState;

  return useShareableState;
}

Expected Behavior:

The route created by createFileRoute should maintain its definition and be correctly resolved, regardless of changes to the generateShareableHook function.

Actual Behavior:

After making changes to the generateShareableHook function, the route.to property in the Home component returns undefined, breaking the routing functionality.

Additional Information:

  • This issue is observed specifically during development and hot-reloading scenarios.
  • The console logs show rendering Home undefined instead of the expected route information.

Environment:

React version: 18
Router library: @tanstack/react-router
Development server: vite

Please look into this issue as it significantly hampers the development workflow. Thank you!

Your Example Website or App

NA

Steps to Reproduce the Bug or Issue

Make any changes in generateShareableHook, this will make the route undefined.

Expected behavior

The route created by createFileRoute should maintain its definition and be correctly resolved, regardless of changes to the generateShareableHook function.

Screenshots or Videos

No response

Platform

  • OS: macOS
  • Browser: Chrome
  • Version: 124.0.6367.208

Additional context

No response

@SeanCassiere
Copy link
Contributor

SeanCassiere commented May 21, 2024

Need a minimal reproduction with the steps required to trigger the behavior you described.

You can create a reproduction using the Router file-based stackblitz starter.

@SeanCassiere SeanCassiere added the information needed Further information is requested label May 21, 2024
@vishal-tiwari
Copy link
Author

@SeanCassiere To reproduce the error as described, please follow the steps below:

  1. Navigate to the provided link: https://stackblitz.com/edit/github-yrgryh.
  2. Wait for the page to load completely.
  3. Use the side-navigation to navigate to the /about page.
  4. Open the global-state-generator.ts file and make a minimal change, such as adding a space or a console.log statement.
  5. Observe that the active link becomes normal, and Route.to starts returning an undefined value.

By following these steps, you should be able to reproduce the issue.

@SeanCassiere SeanCassiere changed the title Route Created by createFileRoute Returns undefined on Development Server After Code Change Route.to becomes undefined after a HMR save May 21, 2024
@SeanCassiere SeanCassiere added bug Something isn't working and removed information needed Further information is requested labels May 21, 2024
@SeanCassiere
Copy link
Contributor

This is an issue with HMR (hot-module-reloading) both with and without codesplitting. The only scenario I wasn't able to reproduce this bug was using the experimental.enableCodeSplitting flag.

This has probably been around for a while but has gone undetected since most folk likely use strings for their navigation.

@vishal-tiwari for the time being I'd recommend using strings for your navigation. HMR bugs are the most difficult to debug You may want to checkout #1353 and see if any solutions from there work for you.

If you are feeling brave, you could try the flag I mentioned above (it's pretty good tbh).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants