如何为使用react-spring实现的React Collapse组件添加defaultOpen默认展开逻辑
React Collapse 组件defaultOpen属性实现方案
核心逻辑思路
你需要同时兼容受控/非受控两种使用模式:首次渲染时优先取传入的isOpen值作为开合状态,没有传isOpen时才用defaultOpen作为初始值;后续组件运行过程中,只要isOpen prop发生变化,就同步更新内部开合状态,实现后续切换由isOpen控制的需求。
具体实现步骤
1. 定义组件Props类型(TS示例,JS可忽略类型定义)
type CollapseProps = { /** 受控模式下的开合状态,传入后优先级高于defaultOpen */ isOpen?: boolean; /** 非受控模式下首次渲染的默认开合状态 */ defaultOpen?: boolean; /** 折叠内容 */ children: React.ReactNode; /** 其他自定义属性,比如动画时长、className等 */ duration?: number; }
2. 内部状态初始化与同步逻辑
import { useState, useEffect, useRef } from 'react'; import { useSpring, animated } from 'react-spring'; const Collapse = ({ isOpen: isOpenProp, defaultOpen = false, children, duration = 300 }) => { // 初始化内部开合状态:优先用传入的isOpen,没有就用defaultOpen const [innerOpen, setInnerOpen] = useState(isOpenProp ?? defaultOpen); // 存储内容真实高度的ref,用来做动画 const contentRef = useRef(null); // 监听isOpen prop变化,同步更新内部状态 useEffect(() => { if (isOpenProp !== undefined) { setInnerOpen(isOpenProp); } }, [isOpenProp]); // react-spring动画配置 const animationStyle = useSpring({ height: innerOpen ? `${contentRef.current?.scrollHeight}px` : '0px', opacity: innerOpen ? 1 : 0, overflow: 'hidden', config: { duration }, }); return ( <animated.div style={animationStyle}> <div ref={contentRef}>{children}</div> </animated.div> ); }; export default Collapse;
3. 组件使用示例
非受控模式(仅用defaultOpen,内部自己管理状态)
const Demo1 = () => { return <Collapse defaultOpen={true}> <p>默认展开的折叠内容</p> </Collapse> }
受控模式(后续开合由外部isOpen控制)
const Demo2 = () => { const [isOpen, setIsOpen] = useState(true); return ( <div> <button onClick={() => setIsOpen(!isOpen)}>切换折叠状态</button> <Collapse isOpen={isOpen} defaultOpen={true}> <p>首次默认展开,后续状态由外部isOpen控制的折叠内容</p> </Collapse> </div> ); }
注意事项
defaultOpen仅在组件首次渲染时生效,组件挂载后修改defaultOpen不会触发任何状态更新- 只要传入了
isOpen属性,组件就会进入受控模式,所有开合状态完全由外部传入的isOpen控制
内容的提问来源于stack exchange,提问作者Ali Moghadami
相关产品推荐
相关产品推荐

