Framer Motion 和 React 路由器 5:如何防止使用嵌套路由重新渲染父组件?

IT技术 reactjs react-router framer-motion
2021-05-09 05:00:59

在下面的示例沙箱中,我有一个父 React Router 渲染两个动画组件。

https://codesandbox.io/s/frame-motion-x-react-router-x-simple-tb1wg?file=/src/Routes.tsx

其中之一包含自己的嵌套链接——每个链接都有自己独立的成帧运动动画。当我单击路由链接时,我需要停止重新渲染嵌套开关的父级。我可以看到问题与在两个级别上使用切换键有关,但我不知道用什么替换它以停止重新渲染更高的组件层次结构。如果我删除键,它会破坏动画。

脚步:

选择关于。注意正确的进入和退出动画。选择联系人。注意正确的进入和退出动画。select Child 1. 注意父组件不需要的重新渲染 select Child 2. 注意父组件不需要的重新渲染 注意:

  • 我添加了一些内联的 Math.random() 调用,它们在重新渲染时会发生变化
  • 我已经包含了一个没有动画的顶级链接来演示嵌套组件按预期安装动画。但是它仍然在重新渲染子链接的选择。

location.pathname 键在选择深层嵌套链接时强制重新渲染。我可以用什么明智地替换它,以便它不会重新渲染?我试过删除它,但这会破坏动画。

谢谢

2个回答

一个更简单的解决方案是使用根路径名作为键。

这样 AnimatePresence 就不会在它从/topics变为/topics/react例如时重新设置开关动画因为密钥仍然是相同的:topics.

<AnimatePresence>
  <Switch location={location} key={location.pathname.split('/')[1]}>
    <Route path="/" exact>
      <Home />
    </Route>
    <Route path="/topics">
      <Topics />
    </Route>
  </Switch>
</AnimatePresence>

您当然可以更进一步,并将其提取到一个函数,该函数将为您提供每个嵌套级别的适当密钥。

const getPathKey = (path, level = 1) => {
  // path: "/topics/react/router"
  // level: 1 -> topics
  // level: 2 -> topics/react
  // level: 3 -> topics/react/router
  return path.split('/').splice(1, level).join('/');
}
<AnimatePresence>
  <Switch location={location} key={getPathKey(location.pathname)}>
    ...
      
      <AnimatePresence>
        <Switch location={location} key={getPathKey(location.pathname, 2)}>
           ...
        </Switch>
      </AnimatePresence>

  </Switch>
</AnimatePresence>

已解决:我已将 location.pathname 替换为带有 useState 的路由器包装器上的组件特定状态键。

https://codesandbox.io/s/framer-motion-nested-routes-react-router-747yw

结果:子路由动画独立于父路由工作,反之亦然。可以通过防止在单个链接上多次重复重新路由来改进。欢迎提出建议。