当状态切换到 React Context 时,使用带有 Chakra UI 的 FramerMotion 的侧边栏动画不起作用

Sidebar Animation using FramerMotion with Chakra UI not working when state is switched to React Context

我正在尝试使用 @chakra-ui/reactGrid 组件创建侧边栏动画以响应 framer-motion。当状态与动画组件在同一个组件内时,动画正在运行。

但是,我想将状态迁移到 ContextProvider,以便我可以从布局内的任何位置切换侧边栏。一旦我将状态移动到 Context,动画就不再工作了。我知道问题是上下文 re-rendering 它是 child。但是我不知道如何使动画与 ContextProvider 一起工作。请帮助我。

如果您想要完整的工作示例,CodesandBox


工作简单示例(如 framer-motion 文档所述)

import { Grid, GridItem, Button } from '@chakra-ui/react'
import { motion, useCycle } from 'framer-motion'

const MotionGrid = motion(Grid)

export function DashboardLayout() {
  const [sidebarState, toggleSidebar] = useCycle('expand', 'collapse')
  const variants = {
    expand: { gridTemplateColumns: '230px 1fr' },
    collapse: { gridTemplateColumns: '55px 1fr' },
  }
  return (
    <MotionGrid
      animate={sidebarState}
      variants={variants}
      gridTemplateRows="80px 1fr"
    >
      <GridItem rowSpan={1} colSpan={2}>
        <Button onClick={() => toggleSidebar()}>ToggleSidebar</Button>
      </GridItem>
      <GridItem>Navbar Here</GridItem>
      <GridItem>Main Content Here</GridItem>
    </MotionGird>
  )
}

切换到 ContextProvider 时示例无效

import * as React from 'react'
import { Grid, GridItem, Button } from '@chakra-ui/react'
import { motion, useCycle } from 'framer-motion'

const SidebarContext = React.useContext({
  sidebarState: 'expand',
  toggleSidebar: () => {},
})
function useSidebar() {
  return React.useContext(SidebarContext)
}
function SidebarProvider({ children }) {
  const [sidebarState, toggleSidebar] = useCycle('expand', 'collapse')
  return (
    <SidebarContext.Provider value={{ sidebarState, toggleSidebar }}>
      {children}
    </SidebarContext.Provider>
  )
}

export function DashboardLayout() {
  const MotionGrid = motion(Grid)
  const { sidebarState, toggleSidebar } = useSidebar()
  const variants = {
    expand: { gridTemplateColumns: '230px 1fr' },
    collapse: { gridTemplateColumns: '55px 1fr' },
  }
  return (
    <MotionGrid
      animate={sidebarState}
      variants={variants}
      gridTemplateRows="80px 1fr"
    >
      <GridItem rowSpan={1} colSpan={2}>
        <Button onClick={() => toggleSidebar()}>ToggleSidebar</Button>
      </GridItem>
      <GridItem>Navbar Here</GridItem>
      <GridItem>Main Content Here</GridItem>
    </MotionGird>
  )
}

// Inside App.js
export default function App() {
  return (
    <SidebarProvider>
      <DashboardLayout></DashboardLayout>
    </SidebarProvider>
  )
}

我得到了答案。这是我常犯的错误。我在 Layout 组件中初始化 MotionGrid 组件,它会在状态更改时触发 re-render 和 re-create 新的 MotionGrid 组件。只需 re-locating 将 MotionGrid 作为单独的组件初始化即可解决问题。


之前

export function DashboardLayout() {
  const MotionGrid = motion(Grid)
  ...
}

之后

const MotionGrid = motion(Grid)

export function DashboardLayout() {
  return (
    <MotionGrid>
    ...
  )
}