react-router 底层使用了 history 库来处理路由。一般有两种选择,一种是使用 BrowserHistory
(背后的实现依赖了 History API),一种是使用 HashHistory
(背后的实现主要依赖 window.location.hash
)。
如果尝试在 HashHistory 上调用 push
API 并传递 state 参数:
var history = HashHistory();
history.push('path', { state: 'value' });
会在 console 看到如下的报错,并且 state 并没有传递成功:
Hash history cannot push state; it is ignored
这个是 history 库的默认行为,具体的代码可以参考 modules/createHashHistory.js
中 push
的代码:
function push(path, state) {
warning(
state === undefined,
'Hash history cannot push state; it is ignored'
);
const action = 'PUSH';
const location = createLocation(
path,
undefined,
undefined,
history.location
);
// ...
上面的代码可以看到,如果传递了第二个参数 state,那么就会输出报错。同时,在 createLocation 函数调用的时候,第二个参数本来应该是 state,这里显式地写成了 undefined
,明确拒绝了传递 state 的做法。
然而,这并不意味着就完全不能传递 state
了。
事实上,push
函数有两种 API 可供选择,一种是 path 是字符串,然后 state 作为第二个参数传递;另一种则第一个参数就是一个对象,其中一个属性就是 state。
如果使用下面的方法调用,state 就可以在 react-router 中被传递了:
hashHistory.push({ path: 'path', state: { state: 'value' } });
但是,需要指出的是。这个只是 state
被传递了,并不代表 state
真的被存储了下来。事实上,HashHistory 并没有依赖浏览器的 History API 功能。因此,这里的 state
传递之后,会出现在 history.location.state
中,但是在浏览器前进/后退的操作中,数据会被丢弃,无法找到。
一个简单的例子是:
var h = createHashHistory();
h.listen((location) => {
console.log(location.state);
});
h.push({ pathname: 'a', state: 1 });
// output: 1
h.push({ pathname: 'b', state: 2 });
// output: 2
h.goBack();
// output: undefined
h.goForward();
// output: undefined
如果将 HashHistory 改成 BrowserHistory,则可以正确输出:
var h = createBrowserHistory();
h.listen((location) => {
console.log(location.state);
});
h.push({ pathname: 'a', state: 1 });
// output: 1
h.push({ pathname: 'b', state: 2 });
// output: 2
h.goBack();
// output: 1
h.goForward();
// output: 2