Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactoring for 9.1. Fixed redirection.
- Loading branch information
1 parent
e3a45bb
commit 62e3824
Showing
29 changed files
with
771 additions
and
618 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
Early attempts at marrying React-Router and Redux built itself upon an idea that React-Router state should be managed by Redux: the current location was part of Redux state and when that part of Redux state changed then the routing would be performed, therefore a user could perform navigation just by `dispatch()`ing an action, and also had an easy access to the current location in Redux state. | ||
|
||
While this is an elegant and smart solution, still I don't feel like React-Router state really belongs to Redux application state. It's like two parallel worlds: the navigation world and the application model world. They don't depend on each other in any way and they're conceptually different and not interconnected. So, I think that React-Router should manage its state by itself. | ||
|
||
Then, one may ask, why is this library using `dispatch()` for redirection and navigation? And for page preloading? | ||
|
||
The answer is: it could easily be some random global variable instead, like `window.__history__` and `redirect()` would just call `window.__history__.replace()`, but, since javascript is single-threaded, on the server side it simply wouldn't work because that global `window.__history__` variable would be shared among all clients which would result in a really weird navigation for all of them. Ok, so the solution is actually simple: just declare some `var history_storage = { history }` and then just pass it around in all functions. This would work, but it would not only introduce a lot of spaghetti code but also would really be a re-implementation of already existing Redux store. And why invent another wheel then. Just use the one you already have if it doesn't interfere (and it doesn't). So that the reason why this library has `dispatch()` for navigation but still doesn't store router state in Redux state. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { location_url } from './location' | ||
|
||
// Creates `history` | ||
export default function create_history(createHistory, location, history_options, server) | ||
{ | ||
// Create `history`. | ||
// https://github.com/ReactTraining/react-router/blob/master/docs/guides/Histories.md#customize-your-history-further | ||
const history = createHistory({ ...history_options, entries: [ location ] }) | ||
|
||
// Because History API won't work on the server side for navigation, | ||
// instrument it with custom redirection handlers. | ||
if (server) | ||
{ | ||
// Instrument `history` | ||
// (which was earlier passed to `preloading_middleware`) | ||
history.replace = server_side_redirect(history_options && history_options.basename) | ||
history.push = history.replace | ||
} | ||
|
||
// Return `history` | ||
return history | ||
} | ||
|
||
// A hacky way but it should work | ||
// for calling `redirect` from anywhere | ||
// inside `@preload()` function argument. | ||
function server_side_redirect(basename) | ||
{ | ||
return (location) => | ||
{ | ||
// Sanity check | ||
if (!location) | ||
{ | ||
throw new Error(`location parameter is required for redirect() or goto()`) | ||
} | ||
|
||
// Convert an object to a textual URL | ||
let url = location_url(location) | ||
|
||
// If it's a relative URL, then prepend `basename` to it. | ||
// (imulates `history` `basename` functionality) | ||
if (url[0] === '/' && basename) | ||
{ | ||
url = `${basename}${url}` | ||
} | ||
|
||
// Construct a special "Error" used for aborting and redirecting | ||
server_redirect(url) | ||
} | ||
} | ||
|
||
export function get_location(history) | ||
{ | ||
// v4 | ||
if (history.location) | ||
{ | ||
return history.location | ||
} | ||
|
||
// v3 | ||
if (history.getCurrentLocation) | ||
{ | ||
return history.getCurrentLocation() | ||
} | ||
|
||
// v2 | ||
let location | ||
const unlisten = history.listen(x => location = x) | ||
unlisten() | ||
return location | ||
} | ||
|
||
export function server_redirect(location) | ||
{ | ||
const url = location_url(location) | ||
const error = new Error(`Redirecting to ${url} (this is not an error)`) | ||
error._redirect = url | ||
throw error | ||
} |
Oops, something went wrong.