telegram-apps icon indicating copy to clipboard operation
telegram-apps copied to clipboard

[Feature]: react-router v6.4 Data APIs integration

Open izzm opened this issue 1 year ago • 10 comments

Is your feature request related to a problem? Please describe.

react-router v6.4 provides new API to routers and new routes definitions. And documentation recommends to use new API https://reactrouter.com/en/main/routers/picking-a-router for a new projects.

Describe the solution you'd like

Ability to use telegram-apps BrowserNavigator along with new react-router API.

Describe alternatives you've considered

Manually show/hide back button using router, initialized by createBrowserRouter method and tracking location using useLocation hook;

const location = useLocation();
const backButton = useBackButton();
const navigate = useNavigate();

useEffect(() => {
  if (location.pathname === "/" && backButton.isVisible) {
    backButton.hide();
  } else if (location.pathname !== "/" && !backButton.isVisible) {
    backButton.show();
  }
}, [location, backButton]);

useEffect(() => {
  backButton.on("click", () => navigate(-1), true);
}, [backButton, navigate]);

Additional context

No response

izzm avatar Jul 22 '24 08:07 izzm

What is the difference with the current implementation?

https://docs.telegram-mini-apps.com/packages/telegram-apps-react-router-integration

heyqbnk avatar Jul 23 '24 05:07 heyqbnk

In 6.4 react-router introduces new Data API with async data loaders and actions, component lazy loading and other stuff https://reactrouter.com/en/main/routers/picking-a-router#data-apis.

This new methods available only while initializing a router in a new way - using function call, for example createBrowserRouter and using RouterProvider component to attach router to the React component tree.

izzm avatar Jul 23 '24 06:07 izzm

But createBrowserRouter creates a BrowserRouter. We don't need it, don't we? We need a router based on a custom navigator. That's why we implemented react-router-integration

heyqbnk avatar Jul 23 '24 16:07 heyqbnk

Yes, we need a custom router. With react-router-integration routes are defined in pre-6.4 style, for example (snippet from documentation):

return (
  <Router location={location} navigator={reactNavigator}>
    <Routes>
      <Route path={'/'} component={IndexPage}/>
      <Route path={'*'} element={<Navigate href={'/'}/>}/>
    </Routes>
  </Router>
);

location and reactNavigator are objects, created by react-router-integration, and it works perfectly. React router version 6.4+ provides new way to attach routes to React component tree, new versions uses RouterProvider component, which allow new features of react router to be used.

New api officially not expose base createRouter method, but it can be imported directly from '@remix-run/router' package (which is not recommended by https://github.com/remix-run/react-router/tree/main/packages/router, but this is the only way I found to implement a custom router). This method get history argument with a type History, which is similar to Navigator, but have few additional properties. location is moved to history property.

For the integration with a new react-router API react-router-integration needs to return an object, compatible with a History type.

izzm avatar Jul 23 '24 18:07 izzm

I create a workaround for 6.4+ style routes definition:

import {
  Action,
  createRouter,
  Path,
  To,
  type History,
} from "@remix-run/router";

...


const navigator = useMemo(() => initNavigator("app-navigation-state"), []);
const [location, reactNavigator] = useIntegration(navigator);

useEffect(() => {
  navigator.attach();
  return () => navigator.detach();
}, [navigator]);

const history: History = {
  location,
  push: reactNavigator.push,
  replace: reactNavigator.replace,
  action: Action.Pop,
  createHref: reactNavigator.createHref,
  createURL: (to: To) => {
    return new URL(reactNavigator.createHref(to), window.location.toString());
  },
  encodeLocation: (to: To) => {
    return (
      reactNavigator.encodeLocation?.(to) ||
      ({ pathname: "/", search: "", hash: "" } as Path)
    );
  },
  go: reactNavigator.go,
  listen: () => {
    return () => {};
  },
};

const routes = ... // define you routes here
const router = createRouter({ routes, history }).initialize();

return (<RouterProvider router={router} />);

Maybe, it will be better to implement this in react-router-integration?

izzm avatar Jul 23 '24 18:07 izzm

listen: () => { return () => {}; },

It works, but the Back button does not respond.

GrayYoung avatar Sep 11 '24 08:09 GrayYoung

I create a workaround for 6.4+ style routes definition:

import {
  Action,
  createRouter,
  Path,
  To,
  type History,
} from "@remix-run/router";

...


const navigator = useMemo(() => initNavigator("app-navigation-state"), []);
const [location, reactNavigator] = useIntegration(navigator);

useEffect(() => {
  navigator.attach();
  return () => navigator.detach();
}, [navigator]);

const history: History = {
  location,
  push: reactNavigator.push,
  replace: reactNavigator.replace,
  action: Action.Pop,
  createHref: reactNavigator.createHref,
  createURL: (to: To) => {
    return new URL(reactNavigator.createHref(to), window.location.toString());
  },
  encodeLocation: (to: To) => {
    return (
      reactNavigator.encodeLocation?.(to) ||
      ({ pathname: "/", search: "", hash: "" } as Path)
    );
  },
  go: reactNavigator.go,
  listen: () => {
    return () => {};
  },
};

const routes = ... // define you routes here
const router = createRouter({ routes, history }).initialize();

return (<RouterProvider router={router} />);

Maybe, it will be better to implement this in react-router-integration?

Any update about this? I use this approach and back button (or navigate(-1)) only changes url but react app doesnt react about that change

oviedo97fer avatar Oct 02 '24 16:10 oviedo97fer

Any update about this? I use this approach and back button (or navigate(-1)) only changes url but react app doesnt react about that change

Try to use navigator.back(); to call navigator, returned by initNavigator. I didn't test this behavior, because I decide to use standard ReactRouter's createBrowserRouter with back button workaload, described in a first message, instead of custom router.

izzm avatar Oct 02 '24 20:10 izzm

Hey guys. I decided to postpone the development of the navigation package (and React router integration as well), so it is better to use the standard React routing utilities for now.

We will go back to this topic after some time

heyqbnk avatar Oct 02 '24 20:10 heyqbnk

Any update about this? I use this approach and back button (or navigate(-1)) only changes url but react app doesnt react about that change

Try to use navigator.back(); to call navigator, returned by initNavigator. I didn't test this behavior, because I decide to use standard ReactRouter's createBrowserRouter with back button workaload, described in a first message, instead of custom router.

Thank you! I finally made the same decision

oviedo97fer avatar Oct 02 '24 21:10 oviedo97fer

We will completely rework it in the future, so I think this issue can be closed.

heyqbnk avatar Apr 05 '25 10:04 heyqbnk