useEffect和onAnimationEnd回调在状态下具有不同的值

时间:2020-01-17 17:33:38

标签: javascript reactjs react-hooks

这是按钮的全部代码。我有涟漪效应的问题。当用户单击按钮时,组件将创建一个新的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;

0 个答案:

没有答案