简体   繁体   中英

Framer Motion and React router 5: How do I prevent re-render of parent components with nested routes?

In the example sandbox below I have a parent React Router rendering two animated components.

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

One of them contains its own nested links - each with their own independent framer-motion animations. I need to stop the parent of the nested switch re-rendering when i click a route link. I can see the problem is related to use of the switch key on both levels but i dont know what to replace it with to stop re-rendering higher up the component hierarchy. If I remove the key, it breaks the animation.

Steps:

select About. note correct entry and exit animations. select Contact. note the correct entry and exit animations. select Child 1. note the unwanted re-render of the parent component select Child 2. note the unwanted re-render of the parent component Notes:

  • i've added some Math.random() calls inline which change on re-render
  • i've included a top level link with no animation to demonstrate the nested components animate on mounting as expected. however it is still re-rendering on selection of child links.

The location.pathname key is forcing re-renders when selecting deep nested links. what can i sensibly replace it with so that it doesn't re-render? Ive tried removing it, but that breaks the animation.

thanks

solved: i have replaced the location.pathname with a component specific state key on the router wrappers with useState.

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

result: the child route animations work indepedently of the parent routes and vice versa. could be improved by preventing multiple repeat re-routes on single links. suggestions welcome.

a simpler solution would be to use the root pathname as the key.

So that AnimatePresence won't re-animate the switch when it changes from /topics to /topics/react for example. Because the key will still be the same: topics .

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

You can of course go further, and extract that to a function that will give you the appropriate key per-nested-level.

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM