场景
基础组件未加出现隐藏显得太生硬,产品要求加些动效
实现
某一项组件的出现和消失,在 React
开发中,一般是通过状态来改变,移除组件往往需要一个中间状态去添加一个类名,所以抽出这部分逻辑作为中间状态。
添加三种状态
- none
- appear(出现)
- leave(消失)
通过一个 visible
状态控制组件的出现和消失:
const STATUS_NONE = 'none';
const STATUS_APPEAR = 'appear';
const STATUS_LEAVE = 'leave';
const defaultDelay = 200
function useAnimateWithVisible(props: {
className: string;
visible: boolean;
delay?: number;
}) {
const { className, visible, delay = defaultDelay } = props
const [status, setStatus] = useState(STATUS_NONE)
const [nextVisible, changeVisible] = useState(visible)
const preVisibleRef = useRef({ visible })
useEffect(() => {
if (visible && !valueRef.current.visible) {
changeVisible(true)
setStatus(STATUS_APPEAR);
} else if (!visible && valueRef.current.visible) {
setStatus(STATUS_LEAVE);
setTimeout(() => {
changeVisible(false)
setStatus(STATUS_NONE)
}, delay)
}
valueRef.current.visible = visible
}, [visible]);
const classNameWrapper = useMemo(() => {
return `${className}__${status}`;
}, [className, status]);
return {
className: classNameWrapper,
visible: nextVisible,
}
}
通过一个延迟给要移除的组件一个临时的状态
使用如下:
function Test() {
const [visible, changeVisible] = useState(false)
const { visible: usedVisible, className } = useAnimateWithVisible(
{ visible, className: 'some-component-wrapper' )
)
return (
<>
<Button
onClick={() => { changeVisible(!visible) }}
>
{!visible ? 'show' : 'hidden' }
</Button>
{usedVisible && (
<SomeComp
className={classnames({ [className]: true, 'some-component': true })}
visible={usedVisible}
/>
)}
</>
)
}
接着为你的组件对应的类名 xx__appear
、 xx__leave
添加样式即可。
还有一种是与列表中移除组件,这类组件是通过列表数据渲染出来的,这种可以通过添加一个实现
function useAnimate(props: {
delay?: number;
className: string
}) {
const { className = '', delay = defaultDelay } = props;
const [status, setStatus] = useState(STATUS_NONE);
useEffect(() => {
setStatus(STATUS_APPEAR);
}, []);
const onLeave = useCallback(() => {
setStatus(STATUS_LEAVE);
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, defaultDelay);
});
}, []);
const classNameWrapper = useMemo(() => {
return `${className}__${status}`;
}, [className, status]);
return {
className: classNameWrapper,
onLeave,
};
}
使用:
function Item(props: {
onDelete: (key: string | number) => void
value: string | number
label: string
}) {
const { label, value, onDelete } = props
const { onLeave, className } = useAnimate({ className: 'item-wrapper' })
return (
<div
className={classnames({
[className]: true,
'item-wrapper': true
})}
>
{label}
<span
onClick={() => {
onLeave().then(() => {
onDelete(value)
})
}}
>
X
</span>
</div>
)
}
在移除之前添加一个延迟,在此过程中的类名更换为 xx__leave
,使用者再对此类名添加css动画样式,也就可以实现对应的动效。
总结
虽然这个hooks实现都很简单,但是给我们带来特别大的便捷。这就是React hooks的魅力所在吧
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。