Giter Site home page Giter Site logo

history's People

Contributors

aaronjensen avatar acdlite avatar agundermann avatar asaf avatar chaance avatar greenkeeperio-bot avatar guidobouman avatar iam4x avatar jeffreywescott avatar jinroh avatar jnv avatar knowbody avatar koba04 avatar liuhanqu avatar lucaas avatar michalkvasnicak avatar microbouji avatar mjackson avatar moox avatar neolegends avatar oliverjash avatar pshrmn avatar pwmckenna avatar ryanflorence avatar taion avatar threepointone avatar timdorr avatar trysound avatar tvervest avatar vslinko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

history's Issues

Add location.delta

Hey. It would be great to know the direction of the transition thus we can set a different animation (with react-router) for forward/back actions. I first though that I can depend on action but browser back/forward buttons are always POP. I would appreciate if we can add this feature, thx?

Queries with MemoryHistory

I am using createMemoryHistory() for server routing(react-router) and createBrowserHistory() for client routing.
Then I have url with queries, on client I can reach a parsed query string in this.props.location.query. But how to reach the same result on server?

I create location object like this


match({location, routes}, (/_..args_/) => {
 // do something
});

Add React Native support

We should introduce a createNativeHistory method that creates a history object that can be used with React Native. Instead of sessionStorage, a native history should use React Native's AsyncStorage module to persist state.

Add API to block the initial "transition"

When createHistory() is called, transition hooks are not invoked. This makes async transitionHooks unsuitable for the data-loading use case. An API like the following would solve this problem:

let history = createHistory();
history.addTransitionHook(...);
history.listen(...);
history.start();

The call to history.start() would then invoke the middleware with the initial location before notifying listeners.

See #50, #22, and #23 for other issues related to supporting data loading via async transition hooks.

Page reload need just like the module 'react-router/lib/RefreshLocation'

For some reason, I would need the SPA page which was based on [email protected] use HTML5 history API on development, but use page reload on production.

const location = process.env.NODE_ENV === 'production'
  ? RefreshLocation
  : HashLocation;

But I saw [email protected] use 'history/lib/createBrowserHistory', so I assume the code could like that

let isSupported = !options.forceReload || supportsHistory(); 

https://github.com/rackt/history/blob/master/modules/createBrowserHistory.js#L24

Thanks!

Restore the URL when POP transitions are canceled

When the user manipulates the URL (either by changing the value in the location bar or using the back/forward buttons) and then does not confirm the transition in the prompt, we should restore the URL to what it was before they changed it. There are a few TODOs in the code about this:

AFAICT this would require us to keep track of a "current" value that would be part of a location's state. This value would be a number that represents the index of that location in the history stack.

For example, if we knew that a given location had a current value of 3, and the previous location had a current value of 6, we could easily calculate that we need to go(3) to restore the URL to what it was before.

@taurose has said before that he is not sure how reliable this would be.

make it easier to disable has history query key

I'm using history in conjunction with react router and redux router. With this setup there is no way to set the queryKey option to false. I'm consistently blowing up my session storage quota.

To initialize the redux router you pass the createHistory function as an argument. createHistory is then called by react router with the default option for queryKey.

I realize this issue has more to do with how these three project are used together, but I figured I would start here.

in app history vs. browser history

Our app has an object detail page that has a back button. We want to set it up so if you visit the page from somewhere in our app the back button will take you back to that page. However if you visit the detail page directly the back button will take you to a default object list page. This currently working using the following:

    if (window.history.length > 1) {
        history.goBack();
    }

However, it does break down in the case that you come to the detail page from an external site. In this case the browser will have history and the back button will take you off our app where we would actually like it to take you to the default object list page.

Is it possible to have a history stack that is only the history within the context of the app that is using history? Basically the first time the app loads that page is treated as the first entry in the stack.

using history in isomorphic environment

I have the setup below for the client environment and server envirnment but get the error:

Uncaught Error: Invariant Violation: Server-side <Router>s need location, branch, params, and components props. Try using Router.run to get all the props you need

my client entry point:

import React          from 'react';
import ReactDOM       from 'react-dom';
import Root           from 'containers/Root';
import configureStore from 'stores';
//import { history }    from 'react-router/lib/BrowserHistory';
import {history} from 'utils/history';

const target = document.getElementById('root');
const store  = configureStore(window.__INITIAL_STATE__);

ReactDOM.render(<Root routerHistory={history} store={store}/>, target);

my server entry point:

import React          from 'react';
import ReactDOM       from 'react-dom/server';
import Router         from 'react-router';
//import Location       from 'react-router/lib/Location';
import routes         from '../routes';
import Root           from 'containers/Root';
import configureStore from 'stores';
import Location from 'history/lib/createLocation';
let _store;

export function getStoreState () {
  return new Promise((resolve) => resolve(_store.getState()));
}

export function render (initialRouterState, initialStoreState) {
  return new Promise((resolve, reject) => {
    try {
      _store = configureStore(initialStoreState);

      const rendered = ReactDOM.renderToString(
        <Root initialRouterState={initialRouterState} store={_store} />
      );

      resolve(rendered);
    } catch (e) {
      reject(e);
    }
  });
}

export function route (request) {
  return new Promise((resolve, reject) => {
    const location = new Location(request.path, request.query);

    Router.run(routes, location, (err, initialState) => {
      if (err) {
        reject(err);
      } else if (!initialState) {
        reject('No initial router state received from React Router.');
      } else {
        resolve(initialState);
      }
    });
  });
}

Give the initial POP location a key

location.key should always be defined, even on the initial POP, just like it is for PUSH and REPLACE. If there is no key, we should replaceState and define one.

Only include query params that are not null

This would greatly simplify setting queries.

E.g.
history.pushState(null, '/path', { thisQueryParam: 'yes', notThisQueryParam: null })
->
/path?thisQueryParam=yes

In other words, include params that are null. In cases an empty param is needed an empty string would be sufficient. I think this is a logical behavior that most developers will understand.

Location key

I think I'm not getting my head around the property "key" of the "location" object. In the docs it says: "A unique identifier for this location".

But I have the following scenario:

  1. The user opens the route /home
  2. History sets location object with the key: "92olpy"
  3. The user go to /about
  4. History sets location object with the key: "vkioqa"
  5. The user goes back to /home
  6. History sets location object with the key: "uipj9o"

Why History gives a different key for the same location?

Support for HbbTV

I'm currently working on an application for HbbTV devices using React and React Router (and therefore this package). After upgrading to React Router v1.0.0-rc, our first history-dependent version, navigation no longer works due to the use of sessionStorage in DOMStateStorage, which fails silently but prevents further execution. Unfortunately when dealing with HbbTV we often find that APIs like this are available on window but are unusable or crippled somehow, making polyfilling them impossible.

We're considering the following workarounds so far:

  • Fork and maintain our own version of history without sessionStorage (cookies instead perhaps?)
  • Fork and wrap sessionStorage calls in try {} catch () {}
  • Extend the Link component and write our own onClick handler which grabs the href from the DOM node and manually navigates to it

The last two options are very quick fixes but sacrifice functionality which is not ideal. Do you have any advice for utilising this package on platforms where sessionStorage exists but throws errors when used?

Fix postinstall npm script on Windows

When installing, the build step complains that
'babel' is not recognized as an internal or external command, operable program or batch file.

I installed babel as a dev dependency in my project and then history was able to install correctly.

Could the build step be changed to run babel from the node_modules instead?

(I'm on Windows btw)

Deprecated warning with Express

I am using the latest history version

"history": "1.12.1",

With Express i am getting the following warning

Warning: createLocation is deprecated; use history.createLocation instead

In the clientside code this was easy to fix

const history = require('history');
const historyObj = history.createHistory();

historyObj.createLocation(....)

When you try to run this code with express you will get the following error

[1] [piping] error given was: Error: Invariant Violation: Browser history needs a DOM
[1]     at Object.invariant [as default] (/var/www/webapp/node_modules/history/node_modules/invariant/invariant.js:44:15)
[1]     at Object.createBrowserHistory [as createHistory] (/var/www/webapp/node_modules/history/lib/createBrowserHistory.js:35:25)
[1]     at Object.<anonymous> (/var/www/webapp/src/server.js:5:28)
[1]     at Module._compile (module.js:434:26)
[1]     at normalLoader (/var/www/webapp/node_modules/babel-core/lib/api/register/node.js:199:5)
[1]     at Object.require.extensions.(anonymous function) [as .js] (/var/www/webapp/node_modules/babel-core/lib/api/register/node.js:216:7)
[1]     at Module.load (module.js:355:32)
[1]     at Module._load (module.js:310:12)
[1]     at Function.module._load (/var/www/webapp/node_modules/piping/lib/launcher.js:32:16)
[1]     at Module.require (module.js:365:17)
[1] [piping] further repeats of this error will be suppressed...

So how can we use createLocation with express?

useBasename results in empty location when matches exactly

When using useBasename together with react-router, initial location that matches basename exactly results in location='' which cannot be matched by react-router to any route. E.g:

<Route component={App}>
  <Route path="/" component={MyComponent} />
</Route>
...
const history = useBasename(createBrowserHistory)({
  basename: '/basename'
});

Entering URL /basename in browser address bar results in
Warning: Location "" did not match any routes

Not sure whether issue is with react-router not matching empty location "/" or with useBasename, mishandling this specific case... Problem can be fixed on useBasename side by simply replacing empty pathname with /

Failure on Install

Getting the following when I'm trying to install this package:

[email protected] postinstall E:\projects\eVision.ShiftVision\src\node_modules\history
node -e "require('fs').stat('lib', function (e, s) { process.exit(e || !s.isDirectory() ? 1 : 0) })" || npm run build

"require('fs').stat('lib',
^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Unexpected token ILLEGAL
at Object. (eval-wrapper:6:22)
at Module._compile (module.js:456:26)
at evalScript (node.js:532:25)
at startup (node.js:80:7)
at node.js:902:3

[email protected] build E:\projects\eVision.ShiftVision\src\node_modules\history
babel ./modules -d lib --ignore 'tests'

modules\Actions.js -> lib\Actions.js
modules\AsyncUtils.js -> lib\AsyncUtils.js
modules\createBrowserHistory.js -> lib\createBrowserHistory.js
modules\createDOMHistory.js -> lib\createDOMHistory.js
modules\createHashHistory.js -> lib\createHashHistory.js
modules\createHistory.js -> lib\createHistory.js
modules\createLocation.js -> lib\createLocation.js
modules\createMemoryHistory.js -> lib\createMemoryHistory.js
modules\DOMStateStorage.js -> lib\DOMStateStorage.js
modules\DOMUtils.js -> lib\DOMUtils.js
modules\enableBeforeUnload.js -> lib\enableBeforeUnload.js
modules\enableQueries.js -> lib\enableQueries.js
modules\ExecutionEnvironment.js -> lib\ExecutionEnvironment.js
SyntaxError: modules/index.js: Unexpected token (1:7)

1 | export createHistory from './createBrowserHistory'
| ^
2 | export createHashHistory from './createHashHistory'
3 | export createMemoryHistory from './createMemoryHistory'
4 | export createLocation from './createLocation

npm ERR! Failed at the [email protected] build script 'babel ./modules -d lib --ignore 'tests''.
npm ERR! This is most likely a problem with the history package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! babel ./modules -d lib --ignore 'tests'
npm ERR! You can get their info via:
npm ERR! npm owner ls history

can't fork and use this npm module via git in package.json

I just submitted a pull request (see #51) to fix the fact that this library strips window.location.hash from the url (which breaks in-page offset navigation when using react-router. Ordinarily, when I find a problem with a library and make a fix, I can just point to my github version of the library and the branch name in my package.json and I'm good to go. But because of the strange build system this library uses, this is not possible, forcing everyone to wait for a new release from the primary author.

Unless I'm missing something (which is entirely possible) ...

Add support for interruptible transitions

Since transitions can now be async, it's possible for a user-initiated transition to occur while a previous transition is still pending.

In modules/createHistory.js#L134, we throw an invariant error if this situation arises. Instead of throwing an error, I think we should simply cancel the pending transition in favor of the new one. This matches native browser behavior.

See #50, #22, and #23 for other issues related to supporting data loading via async transition hooks.

What happens to the fragment identifier when using history.pushState?

Using react-router (1.0.0-rc1) and history (1.9.1), using the History mixin to call this.pushState. I get transitioned to the new state, but fragment identifier seems to be discarded. For example, if take this call to history.pushState:

this.history.pushState(null, '/home#list')

My new location becomes http://whatever/home with no hash.

Feature Request: Expose getCurrentLocation function

I'm using the react-routers match function both client side and server side (I have my reasons). At the moment I'm doing this:

import { createLocation, createHistory } from 'history';

const history = createHistory();
const appLocation = createLocation(
  location.pathname + location.search
);

Which works but isn't very clean IMHO. It would be cool if getCurrentLocation was exposed on the history instance so I can turn the above into:

import { createHistory } from 'history';

const history = createHistory();
const appLocation = history.getCurrentLocation();

As always, I'm willing to submit a PR if authors are interested in this.

add jsnext:main in package.json and include source ('modules')

For better ES6/7 module optimization! See here for more info on jsnext:main and an example here. At least With the source it will be possible to bundle only what is needed using tools like Rollup.

Another reason is mybabelconfig targets ES6 platforms i.e. Atom Electron, nw.js, cordova with crosswalk webview, etc which all have good support for ES6 and thus don't need full transform to ES5.

The changes are tiny so didn't push a PR, basically:
add "jsnext:main": "modules/index.js", and
remove modules from .npmignore (i.e. don't exclude the ES6 source).

If possible would be appreciated!

Better testing stack

It's pretty clear to me at this point that jsdom isn't going to work. The support for the HTML5 history API appears to be incomplete, and, given the quirks of the various history implementations, I'd rather test in real browsers anyway.

Stuff we need to be able to do in a single integration test:

  • Get reliable hashchange/popstate events when the URL changes
  • Use window.history.pushState/window.history.replaceState
  • Use window.location.replace
  • Assign the value of window.location.href

Stuff we need to be able to do in a test suite:

  • Run multiple integration tests without leaking state between them (see #5 (comment))

There are a few options out there, none of which I'm very familiar with. If anyone has any experience with any of these stacks, please chime in.

We use karma to test React Router, so it would be great if we could stick with that. But it seems like I remember it complaining when we tried to change the URL (which is strange because I thought karma ran all your tests in an <iframe> ... ?)

createBrowserHistory throws error in IE9

When using createBrowserHistory IE9 throws an error. Object doesn't support property or method 'replaceState'

This is likely because of the window.history.replaceState({ ...historyState, key }, null, path) call in getCurrentLocation method.

EDIT: this only tested with react-router

Cannot read property 'indexOf' of null

I'm having issues using HashHistory with React Router 1.0-rc1 (I'm also using React 0.13 and Redux 3.0.0).

My Router looks like this:

render((
    <div>
        <Provider store={store}>{() =>
            <Router history={createHistory()}>
                <Redirect from="/" to="/home" />
                <Route component={App} path="/">
                    <Route component={Landing} path="/landing" />
                    <Route component={AuthApp} onEnter={Auth.requireAuth}>
                        <Route component={Home} path="/home" />
                    </Route>
                </Route>
                <Route component={FourOhFour} path="*" />
            </Router>
        }</Provider>
        {debug}
    </div>
), document.getElementById('app'));

But I get this error when running the app on the default "/" route.

Uncaught TypeError: Cannot read property 'indexOf' of nullcreatePath @ useQueries.js:61createLocationFromRedirectInfo @ useRoutes.js:102(anonymous function) @ useRoutes.js:117done @ AsyncUtils.js:13(anonymous function) @ TransitionUtils.js:56(anonymous function) @ TransitionUtils.js:16(anonymous function) @ TransitionUtils.js:54next @ AsyncUtils.js:20loopAsync @ AsyncUtils.js:26runEnterHooks @ TransitionUtils.js:53finishMatch @ useRoutes.js:113(anonymous function) @ useRoutes.js:86done @ AsyncUtils.js:13(anonymous function) @ matchRoutes.js:129(anonymous function) @ matchRoutes.js:98done @ AsyncUtils.js:13(anonymous function) @ matchRoutes.js:129(anonymous function) @ matchRoutes.js:98done @ AsyncUtils.js:13(anonymous function) @ matchRoutes.js:129(anonymous function) @ matchRoutes.js:80getIndexRoute @ matchRoutes.js:31matchRouteDeep @ matchRoutes.js:74(anonymous function) @ matchRoutes.js:127next @ AsyncUtils.js:20loopAsync @ AsyncUtils.js:26matchRoutes @ matchRoutes.js:126(anonymous function) @ matchRoutes.js:92getChildRoutes @ matchRoutes.js:13matchRouteDeep @ matchRoutes.js:87(anonymous function) @ matchRoutes.js:127next @ AsyncUtils.js:20(anonymous function) @ matchRoutes.js:131matchRouteDeep @ matchRoutes.js:108(anonymous function) @ matchRoutes.js:127next @ AsyncUtils.js:20loopAsync @ AsyncUtils.js:26matchRoutes @ matchRoutes.js:126(anonymous function) @ matchRoutes.js:92getChildRoutes @ matchRoutes.js:13matchRouteDeep @ matchRoutes.js:87(anonymous function) @ matchRoutes.js:127next @ AsyncUtils.js:20(anonymous function) @ matchRoutes.js:131(anonymous function) @ matchRoutes.js:104getChildRoutes @ matchRoutes.js:19matchRouteDeep @ matchRoutes.js:87(anonymous function) @ matchRoutes.js:127next @ AsyncUtils.js:20loopAsync @ AsyncUtils.js:26matchRoutes @ matchRoutes.js:126match @ useRoutes.js:82(anonymous function) @ useRoutes.js:248(anonymous function) @ useQueries.js:45(anonymous function) @ createHistory.js:80updateLocation @ createHistory.js:79listen @ createHistory.js:102listen @ createDOMHistory.js:31listen @ createHashHistory.js:153listen @ useQueries.js:42listen @ useRoutes.js:244componentWillMount @ Router.js:92ReactCompositeComponentMixin.mountComponent @ ReactCompositeComponent.js:228ReactPerf.measure.wrapper @ ReactPerf.js:70ReactReconciler.mountComponent @ ReactReconciler.js:38ReactCompositeComponentMixin.mountComponent @ ReactCompositeComponent.js:247ReactPerf.measure.wrapper @ ReactPerf.js:70ReactReconciler.mountComponent @ ReactReconciler.js:38ReactMultiChild.Mixin.mountChildren @ ReactMultiChild.js:192ReactDOMComponent.Mixin._createContentMarkup @ ReactDOMComponent.js:289ReactDOMComponent.Mixin.mountComponent @ ReactDOMComponent.js:199ReactReconciler.mountComponent @ ReactReconciler.js:38ReactCompositeComponentMixin.mountComponent @ ReactCompositeComponent.js:247ReactPerf.measure.wrapper @ ReactPerf.js:70ReactReconciler.mountComponent @ ReactReconciler.js:38mountComponentIntoNode @ ReactMount.js:248Mixin.perform @ Transaction.js:134batchedMountComponentIntoNode @ ReactMount.js:269Mixin.perform @ Transaction.js:134ReactDefaultBatchingStrategy.batchedUpdates @ ReactDefaultBatchingStrategy.js:66batchedUpdates @ ReactUpdates.js:110ReactMount._renderNewRootComponent @ ReactMount.js:404ReactPerf.measure.wrapper @ ReactPerf.js:70ReactMount.render @ ReactMount.js:493ReactPerf.measure.wrapper @ ReactPerf.js:70startApp @ app.js:77Channel.fire 

The failure is coming from this line in the createPath function of the useQueries file.

 return history.createPath(pathname + (pathname.indexOf('?') === -1 ? '?' : '&') + queryString);

Apparently, my <Redirect /> is causing the pathname to be null for some reason. Why would this be happening?

Transition Middleware

I'd like to hook into history to do data loading. To do this, I need to be able to pause a transition while data loading is occurring.

I think this can be simulated today using registerTransitionHook() and a custom getUserConfirmation() handler that doesn't actually show a user confirmation dialog. This is of course a hack.

A better solution would look something like this:

let history = createBrowserHistory();
history.registerTransitionMiddleware(function(nextLocation, prevLocation, fnNext, fnAbort) {
   fetchSomeData(location).then(fnNext);
});

The transition would simply freeze until fnNext or fnAbort are called.

If the direction sounds good, then I could submit a PR for this.

Using absolute URL in pushState() doesn't work

The most minimal test case I could come up with:

import {createHistory} from "history/lib/createBrowserHistory";
let history = createHistory();
history.listen(loc => console.log(loc.pathname));
history.pushState(null, window.location.href);

The browser goes to the right location, but the pathname printed in the console (after pushState is called) is wrong.

From https://developer.mozilla.org/en-US/docs/Web/API/History/pushState:

The new URL does not need to be absolute; if it's relative, it's resolved relative to the current URL. The new URL must be of the same origin as the current URL; otherwise, pushState() will throw an exception. This parameter is optional; if it isn't specified, it's set to the document's current URL.

I often run apps on the same host but different base paths. I worked around this by parsing the pathname out of the URL before calling pushState.

Support data-loading via async transition hooks

In issue #22, I proposed adding support for async transitions via transition middleware. I also created a POC implementation in #23. While the PR was not merged due to a lack of design consensus, similar functionality was subsequently added in ae8dd6f in the form of async transition hooks.

The current implementation has a couple of limitations, however, that make it unsuitable for my use case. I'm creating this issue to re-open the discussion around async transitions building on @mjackson's work. My hope is that the current transitionHook interface can be extended in such a way that it becomes a suitable approach to achieving async data loading.

Limitation of current transition hook design:

  1. When createHistory() is called, transition hooks are not invoked

    This makes transitionHooks unsuitable for the data-loading use case. An API like the following would solve this problem:

    let history = createHistory();
    history.addTransitionHook(...);
    history.listen(...);
    history.start();

    The call to history.start() would then invoke the middleware with the initial location before notifying listeners.

  2. Interrupted transitions aren't supported

    Since transitions can now be async, it's possible for a user-initiated transition to occur while a previous transition is still pending.

    In modules/createHistory.js#L134, we throw an invariant error if this situation arises. Instead of throwing an error, I think we should simply cancel the pending transition in favor of the new one. This matches native browser behavior.

export a function for locations comparing

Does exists any functions can we compare equal between two locations?

Maybe should exist a function like this:

export function locationEquals(location1, location2) {
  if (location1 && location2 && location1.key && location2.key) {
    return location1.key === location2.key;
  }
  return false;
}

Docs do not reflect the actual types of histories available

The docs indicate three types of histories:

  • createHistory
  • createHashHistory
  • createMemoryHistory

In the code, there are two more:

  • createBrowserHistory
  • createDOMHistory

createBrowserHistory seems to actually be what the docs claim createHistory is, so it's unclear what createHistory actually does.

Opting out of beforeunload and using BFCache

I think it would be great to allow opting out of using beforeunload for the following reasons:

  1. Usability is controversial. Personally, I would avoid it in most cases and save the data to localStorage to restore it on the next visit rather than annoying the user with a modal when he tries to close the browser window. There's even a discussion about disabling it by default at bugzilla.
  2. It comes with the non-apparent side effect of disabling BFCache which freezes the DOM and scripts when the page is left so they can be quickly restored/resumed when navigating back to the page.

Incidentally, using beforeunload to disable BFCache fixes this bug which occurs when re-entering the cached page at a different URL. But as far as I can tell we can fix this in a better way by using the pageshow event. Something like

function pageShowListener(event) {
  if (event.persisted)
    history.transitionTo(getCurrentLocation());
} 

That way, when using a browser with BFCache, re-entering our app at the same URL wouldn't require any re-renders, and re-entering at a different URL would allow for render optimizations such as React's reconciliation (DOM diffing).

QuotaExceededError in Safari incognito mode

When using safari in incognito mode, navigation fails with the following exception:

QuotaExceededError: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota.

Safari denies usage of local/session storages when in incognito mode, and raises this error when you try to.

I am using the BrowserHistory history and it seems like the error stems from history/DOMStateStorage.

iOS Chrome createBrowserHistory.goBack BUG

Initial data:

Device: iPhone 5
OS: iOS v9.0.1
Browser: Chrome v45.0.2454.89
Bootstrap code:

import { createBrowserHistory } from 'history' // v1.11.0

const history = createBrowserHistory()

Steps to reproduce:

  1. Go to www.google.com
  2. Go to our site
  3. Invoke history.pushState(null, '/demo/path1')
  4. Invoke history.pushState(null, '/demo/path2')
  5. Invoke history.goBack()

Expected result:

The history goto our site /demo/path1

Actual result:

The history goto www.google.com

P.S.: It is work fine in Safari.

Add bower support?

Why only npm and not bower support? I used react-router with bower, so it doesn't make any sense to me why you guys don't have it supported.

Transition API

After registering a transition hook, there are two cases when transitioning away from a location:

  1. the user does something to cause onbeforeunload (like closing the window)
  2. the user does something to transition somewhere else in the app

In the case of (1), the only thing we can do is provide a string to onbeforeunload to get a confirmation from the user (https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload).

In the case of (2) we could allow the developer to do anything they want.

Currently history only handles case (1) with a bit of indirection between creating the history and registering hooks.

A strawman API to allow for both, and remove the indirection could look something like:

// callback with a string and both cases get a confirmation dialog
history.registerTransitionHook((isUnload, cb) => {
  cb("you sure you want to leave?");
});

// if you want to do something fancy for case (2)
history.registerTransitionHook((isUnload, cb) => {
  // if its an unload event you must do things synchronously
  if (isUnload) {
    cb("you sure?")
  }
  else {
    // do something fancier than window.confirm
    cb(true) // allow the transition
    cb(false) // cancel the transition
  }
});

With this API there would be no need for getUserConfirmation and we could allow devs more freedom when transitioning inside the app instead of restricting them to the constraints of onbeforeunload in all cases.

Add `baseHref` or `rootUrl` for React-Router

I have an app that is mounted at /myapp/section.

I'd love to be able to specify a rootUrl in order to avoid the below code. If you're on board I can happily issue a PR.

I currently have to specify the baseUrl like this when using React-router:

let base = '/myapp/section';

render() {
    return (
        <div>
            <Link to={`${base}/about`}>About</Link>
            {this.props.children}
        </div>
    )
}
...

<Router history={history}>
    <Route path={`${base}/`} component={MainContainer}>
        <IndexRoute component={SecondPage} />
        <Route path={`${base}/thirdPage`} component={thirdPage}/>
    </Route>
</Router>

Add scroll position support

We need to add a getScrollPosition option to history objects so we can store the scroll position before navigating to a new page. Location objects should have this data in the scrollX and scrollY properties.

var history = createHistory({
  getScrollPosition() {
    return { x: 0, y: 0 };
  }
});

history.listen(function (location) {
  console.log(location.scrollX, location.scrollY);
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.