当状态切换到 React Context 时,使用带有 Chakra UI 的 FramerMotion 的侧边栏动画不起作用
Sidebar Animation using FramerMotion with Chakra UI not working when state is switched to React Context
我正在尝试使用 @chakra-ui/react
的 Grid
组件创建侧边栏动画以响应 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>
...
)
}
我正在尝试使用 @chakra-ui/react
的 Grid
组件创建侧边栏动画以响应 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>
...
)
}