React中使用framer-motion时,如何避免MotionComponent不必要重渲染?
避免React组件中动画组件的不必要重渲染
原问题代码
const App = () => { // state here const [state,setState] = useState([]); const handleClick = (item) => { setState(prev=> [...prev, item]); // 修正原代码语法错误 } return ( <> <MotionComponent/> // 执行重复动画的组件 <StateComponent handleClick={handleClick}/> // 点击更新state,触发App重渲染导致MotionComponent也重渲染 </> ) }
问题:StateComponent的点击事件更新App组件的state时,会导致App重渲染,进而让不依赖任何state/props的MotionComponent也跟着重渲染,打断或重复触发动画,如何避免?
解决方案
1. 用React.memo包裹MotionComponent
React.memo是高阶组件,会对组件的props做浅比较,若props无变化则跳过重渲染。由于MotionComponent未接收任何props,App重渲染时它不会跟着更新。
修改后代码:
import { memo } from 'react'; // 用memo包裹动画组件 const MemoizedMotionComponent = memo(MotionComponent); const App = () => { const [state,setState] = useState([]); const handleClick = (item) => { setState(prev=> [...prev, item]); } return ( <> <MemoizedMotionComponent/> <StateComponent handleClick={handleClick}/> </> ) }
2. 将MotionComponent提取到App组件外部
如果MotionComponent不需要访问App内部的state、props或上下文,可将其移到App组件外部。此时App的重渲染不会影响它,因为它不在App的渲染范围内。
修改后代码:
// 把动画组件放在App外部 const MotionComponent = () => { // 动画逻辑 return <div>重复动画内容</div>; }; const App = () => { const [state,setState] = useState([]); const handleClick = (item) => { setState(prev=> [...prev, item]); } return ( <> <MotionComponent/> <StateComponent handleClick={handleClick}/> </> ) }
3. 优化handleClick函数(附带优化StateComponent的重渲染)
虽然核心问题是MotionComponent,但StateComponent也可能因handleClick的引用变化而重渲染。用useCallback缓存函数引用,结合React.memo包裹StateComponent,可进一步优化整体性能。
修改后代码:
import { memo, useCallback } from 'react'; const MemoizedMotionComponent = memo(MotionComponent); const MemoizedStateComponent = memo(StateComponent); const App = () => { const [state,setState] = useState([]); // 用useCallback缓存handleClick,依赖项为空因为setState是稳定引用 const handleClick = useCallback((item) => { setState(prev=> [...prev, item]); }, []); return ( <> <MemoizedMotionComponent/> <MemoizedStateComponent handleClick={handleClick}/> </> ) }
内容的提问来源于stack exchange,提问作者LittleTeemo
相关产品推荐
相关产品推荐

