缓存 React-Router 路由

8

I have the following code:

<View>
  <Header />
  <List />
</View>

如果用户点击列表项中的编辑按钮,react-router 会将页面从 /list 更改为 /list/{itemId}。这是一个新页面。用户填写了一些信息并单击保存后,react-router 会切换回 /list。现在整个/list 页面都被重新渲染了!
是否有一种缓存页面的方法,使得react 可以检测到更改并只重新渲染更改的内容,而不是再次渲染整个页面?
应该也可以直接显示页面(而非通过/list -> /list/{itemId}),因此我认为不需要使用modal 解决方案。
我正在使用react-router-redux v5.0.0-alpha.9,因此解决方案应与其兼容。它还应与react-nativereact-dom兼容。

1
这不是react-router直接支持的功能,但是<Route>组件确实有一个render属性,您可以使用它来显示/隐藏组件,而不是在导航到新路由时卸载它的默认行为。请参见https://github.com/ReactTraining/react-router/issues/4888。我不确定timdorr所说的“这很可能会产生意想不到的副作用”是什么意思,但我想在这种情况下应该没问题(除非您在所有地方都这样做)。 - Matt Browne
2个回答

4

如果你正在使用react-router

在使用Route时,组件在前进或后退时无法缓存,这会导致数据和交互的丢失

当路由不匹配时,组件将被卸载

我们研究了Route的源代码后发现,使用children属性作为函数可以帮助控制渲染行为。

隐藏而不是移除可以解决这个问题。

我已经使用我的工具react-router-cache-route修复了这个问题。

用法

<CacheRoute>替换<Route>

<CacheSwitch>替换<Switch>


如果您想要真正的<KeepAlive />用于React

我有自己的实现react-activation

在线演示

用法

import KeepAlive, { AliveScope } from 'react-activation'

function App() {
  const [show, setShow] = useState(true)

  return (
    <AliveScope>
      <button onClick={() => setShow(show => !show)}>Toggle</button>
      {show && (
        <KeepAlive>
          <Test />
        </KeepAlive>
      )}
    </AliveScope>
  )
}

enter image description here

实现原理很容易说。

由于React会卸载嵌套组件,我们需要提取<KeepAlive>中的组件(即它们的children props),并将它们渲染到不会被卸载的组件中。


2

最近遇到了同样的问题,我的第一反应是使用类似于react-router-cache-route或其他包。

但第三方包的主要缺点是它们通常很慢地支持新的react-router版本,而且源代码对我来说过于复杂。

所以我进一步研究,并偶然发现了来自Dan Abramov的这个建议,最终得到了以下解决方案:

function App() {
  const itemId = useParams<{ itemId: string }>();

  return (
    <Switch>
       ...
       <Route
          exact
          path={['some-list-route', 'some-list-route/:itemId']}
       >
          <List style={itemId ? { display: 'none' } : undefined} />
          {itemId && <ListItem />}
       </Route>
       ...
    </Switch>
  )
}

我们将listitem路由都放在单个Route组件下,以便控制它们的挂载行为。当我们进入item路由时,我们隐藏了<List />(但它仍然被挂载,“kept-alive”),并有条件地挂载<ListItem />
如果需要更多控制,例如只对list路由有条件地触发数据获取,我们还可以将itemId作为prop传递给<List />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接