Вот весь код кнопки. У меня проблема с волновым эффектом. Когда пользователь нажимает кнопку, компонент создает новую сущность rippleElements
для визуализации. На данный момент все хорошо. После окончания анимации вызывается onAnimationEnd
. Проблема в том, что у меня нет последнего добавленного элемента в rippleElements
. Почему? Элемент отрисован, анимация завершена, но состояние не обновлено? Как видите, у меня 2 console.log
. Первый в useEffect
и показывает правильные значения. Но второй, который находится в onAnimationEnd
, имеет неправильное значение, и что console.log
запускается ПОСЛЕ первого. В чем дело? :)
import { omit } from 'underscore';
import React, { FunctionComponent, ButtonHTMLAttributes, useState, useEffect } from 'react';
import uuid from 'uuid/v4';
import classnames from 'classnames';
export interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
primary: boolean,
ripple: boolean,
additionalClass?: string,
}
const Button: FunctionComponent<Props> = (props) => {
const [rippleElements, setRippleElements] = useState<JSX.Element[]>([]);
useEffect(() => {
// 1, actual - 1
console.log(rippleElements, rippleElements.length)
}, [rippleElements]);
const {primary, ripple, additionalClass, children} = props;
const classNames = classnames(
'btn',
{
primary
},
{
'with-ripple': ripple
},
additionalClass
);
function onAnimationEnd(key: string) {
console.log(rippleElements.length) // 0, actual - 1
// setRippleElements(rippleElements.filter(element => element.key !== key));
}
function newRippleElement(d: number, left: string, top: string) {
const key = uuid();
return (
<div
key={key}
className="ripple"
style={{width: d, height: d, left, top}}
onAnimationEnd={() => onAnimationEnd(key)}
>
</div>
);
}
function renderRippleElements() {
return rippleElements;
}
return (
<button
className={classNames}
{...omit(props, ['additionalClass', 'primary'])}
onClick={(event) => {
if (props.onClick) {
props.onClick(event);
}
if (ripple) {
var rect = event.currentTarget.getBoundingClientRect();
const d = Math.max(event.currentTarget.clientWidth, event.currentTarget.clientHeight);
const left = event.clientX - rect.left -d/2 + 'px';
const top = event.clientY - rect.top - d/2 + 'px';
const rippleElement = newRippleElement(d, left, top);
setRippleElements([...rippleElements, rippleElement]);
}
}}
>
{children}
{renderRippleElements()}
</button>
);
}
export default Button;