react-router-v4不再支持query持久化

当我在书写以下代码时, 发现跳到app-detail页面后 this.props.location.query对象里有id, isEdit属性, 但url上并没有带query参数

1
2
3
4
5
6
7
this.props.dispatch(routerRedux.push({
pathname: '/app-detail',
query: {
id: row.id,
isEdit
}
}))

究竟是怎么回事?

前因后果

react-router-redux5.x版本开始,变成react-router的一部分,代码库都转移至react-router去了, 它只支持react-router 4.x

react-router 4.x 的API变化很大, 其中就有一项, 不再支持qeury string

具体可见后面的issue,这里涉及到设计理念的问题,不是文本讨论的重点。

这里要意识到的问题是, 前文的代码虽然设置的query,在/app-detail路由对应的组件也的确可以通过this.props.location.query来获取, 但query的值并没有反应到url上,也即query值是放在内存里的,状态是非持久的,一刷新页面,query的值就没有了,这样经不起刷新的页面是不可靠的。

所以必须想个办法解决它。

解决方案

match.params

修改路由配置,使用match.params

1
2
3
4
5
6
7
this.props.dispatch(routerRedux.push({
pathname: `/app-detail/${row.id}/${isEdit}`,
query: {
// id: row.id,
// isEdit
}
}))

这样可以从this.props.match.params对象中拿到的id, isEdit, 要注意的是变量类型为字符串。

这是最简单的解决方案,优点是不用引第三方库,缺点是每次添加参数都需要修改路由配置,参数顺序还不能写错; 如果参数一多,就会麻烦且容易出错

location.search + 引入querystring解析库

前文的代码改写成

1
2
3
4
this.props.dispatch(routerRedux.push({
pathname: '/app-detail',
search: `id=${row.id}&isEdit=${isEdit}` // 这里不需要写问号?
}))

在需要使用search的时候

1
2
3
import querystring from 'any-query-string-lib-you-want'

let {id, isEdit} = querystring.parse(this.props.location.search)

这样的优点是,不需要修改路由规则,参数再多也不用担心顺序的问题,缺点当然是,要引入第三方库。

参考资料

react-router issues

react-router-redux

Fork me on GitHub