reach / router

https://reach.tech/router
MIT License
6.9k stars 326 forks source link

Support Hash History? #25

Closed oferitz closed 6 years ago

oferitz commented 6 years ago

In React router you can do something like this:

import createHashHistory from 'history/createHashHistory'
<Router history={history}>
 <Routes />
</Router>

Is this supported?

This is very useful in environment like Electron where you can't use the "normal" HTML5 history API.

I didn't found anything in the docs except from this: https://reach.tech/router/api/createHistory but it doesn't seems related to what i'm looking for.

ryanflorence commented 6 years ago

No it's not.

In electron you can use a memory history instead of hash, yeah?

import {
  createMemorySource,
  createHistory,
  LocationProvider
} from "@reach/router"

let source = createMemorySource("/starting/url")
let history = createHistory(source)

let App = () => (
  <LocationProvider history={history}>
    <Router>
      {/* ... */}
    </Router>
  </LocationProvider>
)
oferitz commented 6 years ago

Thanks.

The memory history will probably work, but would you consider a PR that add support for hash history also?

ryanflorence commented 6 years ago

No. Hash history has a lot of edge cases that I don't want to deal with, but if you look at the source of createMemorySource you can see what you need to make a createHashSource.

will-stone commented 6 years ago

@oferitz I'd quite like this too. If you work on a Reach add-on to support hash history, do you mind posting it here so others may use it too?

And thanks Ryan for providing this router. It's definitely the easiest to use to-date.

oferitz commented 6 years ago

@will-stone If i understood @ryanflorence correctly, he will not consider any PR for adding hash support. so i didn't started any work on such thing. i actually found that memory history could work on my use case (Electron).

will-stone commented 6 years ago

Okay, thanks @oferitz, I'll look into it myself if I get time.

will-stone commented 6 years ago

@oferitz I've had a go at creating my own hash source: https://github.com/will-stone/hash-source

@ryanflorence I know you said you wouldn't be officially supporting this but I'd really appreciate it if you could do a quick once-over of the code (there's not a lot there) and let me know if there's any glaring omissions, or is just not the way it should be handled. Thanks.

nickserv commented 6 years ago

Wow, you can use the same LocationProvider with a different history source? This looks very promising, thanks @will-stone. Please ping me when it's published or if you need any help.

will-stone commented 6 years ago

@nickcolley it has been published: https://www.npmjs.com/package/hash-source

I've put together a sandbox to demo it: https://codesandbox.io/s/30yj1213m However, the back/forwards functionality doesn't work on the sandbox (it did on my local tests). Which means we may need to use onHashChange. Anyway, if anybody would like to help out, please log issues/PRs on its repo and save Ryan from the noise on here.

edit: loading in separate window demonstrates it properly: https://30yj1213m.codesandbox.io/#/

jimthedev commented 6 years ago

Yeah @will-stone I was doing some things with hash previously and recall codesandbox not liking it.

j3l11234 commented 5 years ago

I also write a lib for use reach/router with hash. and also publish it look the similar to @will-stone . I think the reach/router just use a little part of location api and history api, so create a hash histroy is easy. I will update it continuously feel free to add issue

https://github.com/j3l11234/reach-router-hash-history https://www.npmjs.com/package/reach-router-hash-history

will-stone commented 5 years ago

@j3l11234 Hmmm... I'm not sure how I feel about that. Does yours offer anything over mine? It looks very similar. Some comments and functions are identical! If anything is missing, I'm happy to accept PRs and issues. It's not even forked or credited in the README. I'd say you've scored badly on open source etiquette.

raveenakothapally commented 5 years ago

@ryanflorence - I don't think createMemorySource persists state across refreshes which can be annoying during development. Would appreciate if memory is preserved across page refreshes.

FYI. This will not be a problem for hash routers or browser routers as the href on refresh won't change.

One workaround I could think of -

const REACH_ROUTER_LOCATION = "<SOME_STORAGE_KEY>";
const path = localStorage.getItem(REACH_ROUTER_LOCATION);

let source = createMemorySource(path || "/");
let history = createHistory(source);

const RootReachNode = () => (
  // You could also use a useEffect/unmount hook to capture pathname if this is not root node
  <LocationProvider history={history}>
      {...}
  </LocationProvider>
);

window.addEventListener("beforeunload", () => {
  localStorage.setItem(REACH_ROUTER_LOCATION, history.location.pathname);
});
j3l11234 commented 5 years ago

@will-stone Im sorry about that,In fact, that was not my intention. you can find the previous commit. I use another way to fix it. I want to make hash history similar to history, such as the overide addEventListener, I rewrite popstate to hashchange. I will simulate the state like history later. I will add the credit for you and I sincerely apologize for that again.

andreiglingeanu commented 5 years ago

@will-stone thanks! Works fine for my use case.

gaoxiaoliangz commented 5 years ago

I created a forked version for my use case https://github.com/gaoxiaoliangz/router. Just add useHashRouting to the Router component and you are good to go.

hardcoremore commented 5 years ago

One rookie question though. If reach router is not using hash to prevent page reload how you supposed to keep redux state?

Isn't the idea of react to create single page web applications so that you do not have to reload everything on each page change? If we are reloading everything when changing page what is the purpose of the react than I can use jQuery as well.

nickserv commented 5 years ago

The HTML5 History API (specifically History.pushState()) allows you to change the URL without reloading, as if the user navigated normally. Most routing libraries including Reach Router use this to simulate navigation in SPAs without full reloads. Hash history is just an alternate URL syntax for browsers that don't support HTML5 History.

hardcoremore commented 5 years ago

Yeah, that is true. Except when user wants to change route manually than page is reloaded. For example if I am on route example.com/#home and I change url in the address bar to example.com/#report the page will not be reloaded. But if you do not use hash and change url in the address bar the page will reload.

hardcoremore commented 5 years ago

@will-stone Hey will, this hash history is working great, but how can I use navigate function with it?

If I use navigate it stops using hash completely and it just redirects like regular link.

hardcoremore commented 5 years ago

The HTML5 History API (specifically History.pushState()) allows you to change the URL without reloading, as if the user navigated normally. Most routing libraries including Reach Router use this to simulate navigation in SPAs without full reloads. Hash history is just an alternate URL syntax for browsers that don't support HTML5 History.

But everytime I use navigate function or Link component the page reloads completely and all state of the app is lost. How can I prevent this (without using hash history) ?

will-stone commented 5 years ago

Hi @hardcoremore, thanks for the praise. Do you mind raising any issues you have with hash-source on the repo itself? If you include a codesandbox/demo-repo that would greatly help with debugging the issue.

hardcoremore commented 5 years ago

Hi will, yes I will open the ticket on the repo.

Thanks

lsps9150414 commented 5 years ago

@hardcoremore Hi, have you found the solution to this? It will be a great help if you could share your findings, thanks!

But everytime I use navigate function or Link component the page reloads completely and all state of the app is lost. How can I prevent this (without using hash history) ?

Akiyamka commented 5 years ago

@nickmccurdy

Hash history is just an alternate URL syntax for browsers that don't support HTML5 History.

You are not right, there is a huge difference between them. In case we have link without hash (some.site/about/ for example) after page refresh or reopen tab, or if you share that link - browser create GET request to some.site/about/index.html. By default static server return 404 error on this request because entry point with js who handle routing located in some.site/index.html.

Of course it can be fixed after some back-end reconfiguration for redirect requests, however, we have many cases when we do not have access to do this (surge.sh, github pages, netlify, etc.)

Hash routing does not require any additional configuration to work because some.site/#/about/ create correct request to some.site/index.html

Akiyamka commented 5 years ago

@j3l11234 thx, your package help me

emilioplatzer commented 5 years ago

Most HTML5 Offline applications needs hash route, because you must list all of your paths in the app.manifest resource.

asktree commented 5 years ago

I am in the situation that @Akiyamka outlines; I use static hosting, need my users to be able to open mysite.com/img/[image_id] in a new tab, and there's no way to do this AFAIK without using react-router or SSRing all 1m of my images.

nickserv commented 5 years ago

Please consider making it easier to use this, I use GitHub Pages on all my open source project sites and it's significantly more difficult to set up Reach Router with hash routing than to use another router that supports it, but I need Reach Router's accessibility features

prionkor commented 4 years ago

I tried to use solutions provided here and as well as the package reach-router-hash-history. I couldn't use navigate() function because state wasn't propagated with the hash history.

I have rewrite hash history code and made a gist that fixes the problem. I am putting it here if anybody needs it.

https://gist.github.com/prionkor/59215ff78de7b706fbb6b97a9a61b578

nickserv commented 4 years ago

FYI almost a year has passed since my last comment. From what I remember, Reach Router's development has slowed down and new features will likely not be added. Instead, it's recommended to migrate to React Router 6, which is based on some of the API improvements of Reach Router. It also has a HashRouter component built in.