React-Router如何在页面刷新后保持位置状态?

时间:2018-07-13 21:55:53

标签: reactjs react-router

我很困惑。

我有一个工作流程,有人可以开始填写产品表单。这是一个很长的格式,我想在输入时将进度保存到服务器(但要等到填满一点之后再保存)。因此,我们从创建表单的URL开始,在他们键入了一点之后,我们在服务器上发布了POST以创建资源,在请求完成之后,我们将URL更新为具有新ID的编辑路径。 / p>

换句话说,您开始在网址/product处填写表格,然后在填写了一段时间后,网址移至/product/123。之后,加载该URL将为您提供表单。

所以基本上我有

<Route path={`/product`} exact component={CreateProduct} />

<Route exact={true} path="/product/:productId" render={({
      match: {params: {productId}},
      location: {state: {data}={}}
  }) => (
    <EditProduct productId={productId} initialData={data} 
  )} />

看到那个状态?那是因为我从创建模式切换到编辑模式的方式是这样的

const id = await apiFetch(`/api/product`, data, {method: `POST`})
this.props.history.push({pathname: `/product/${id}`, state: {data} })

在我拥有的<EditProduct>组件的构造函数中

constructor({productId, initialData}) {
   this.super()
   this.state = {}
   if(initialData)
     this.setState({data: initialData})
   else
     getProduct(productId).then(({data}) => this.setState({data}))
}

这样做,<EditProduct>组件中的初始数据就被植入<CreateProduct>组件中,而我不需要从服务器或其他任何东西上重新加载它。

这有效,过渡很顺利,URL更新了,一切都很笨拙。

我现在可以继续编辑<EditProduct>组件,并且可以正确保存。我可以打开一个新标签到相同的URL,它会加载所有内容,然后我可以继续。发生这种情况的原因是,在这种情况下,initialDataundefined,因此它是从服务器加载的。是的!

但是

如果我改为刷新原始标签,事情会变得很奇怪。自保存以来累积的所有更改都将丢失。在调试器中深入研究,我发现问题是从initialData对象传递的location.state.data不是空的-它是首次创建产品时的初始对象。

那么它到底来自哪里?我只是做了整页刷新(甚至是没有打开缓存和devtools的“硬”刷新)。该数据不在URL中(实际上,将URL粘贴到同一窗口中的另一个选项卡中的复制不存在此问题)。

我知道的唯一机制可以在刷新之间保留数据,但不能持久保存到这样的新选项卡上,sessionStorage是这样,但是当我在控制台中检查它时,会被告知

> sessionStorage
< Storage {length: 0}

我什至认为,也许React Router会在页面卸载之前和页面加载之后操纵会话存储,但是在我的JavaScript包的第一行中断显示的是完全相同的东西。

那么这种持久性到底是怎么发生的呢??

2 个答案:

答案 0 :(得分:0)

我有一个非常相似的问题,同样的困惑。

window.history.replaceState()

解决了

我有一个简单的搜索表单,该表单重定向到第二页,并使用路由器的位置状态重新填充第二页上的搜索输入。

在这种情况下,发生了这种情况:

  1. 在第一页上搜索“ foo”->重定向至第二页,并查看“ foo”的搜索结果。
  2. 在第二页上搜索“栏”。 ->查看“酒吧”的结果。
  3. 点击刷新。期望?搜索栏为空,或者搜索+结果为“栏”。 ->相反,请查看“ foo”(??)的搜索+结果

我通过这样做来解决此问题,以便每次用户在第二页上进行搜索时,我使用正确的搜索词替换window.history.replaceState的状态。这样,刷新将为用户提供预期的搜索。在第二页的每次搜索中都用一个空对象替换状态也可以很好地工作,使用户每次刷新时都得到一个空搜索。

答案 1 :(得分:0)

我相信提问者已经解决了这个问题,尽管答案已隐藏在评论中。

问题实际上出在这里:

用户重新加载页面时state来自哪里? state指的是props.location.state提供的react-router

TLDR; state不是普通的javascript实现,它绑定到浏览器环境

BroswerRouter的{​​{1}}直接使用基础的本机浏览历史记录API,因此历史记录API已绑定到平台,您无法根据正常规则预测其行为。

这是特殊的部分:

状态对象可以是任何可以序列化的对象。由于Firefox将状态对象保存到用户的磁盘上,因此可以在用户重新启动浏览器后将其还原

大多数用户将react-router视为普通的javascript,因此存在问题