在状态更改时反应中的动画按钮



我试图做一个按钮,当发生某些事情时(onclick,http成功/错误)动画标签。但是我不知道如何应用这些类并找到一种优雅的方式来通过组件状态处理它。

单击按钮时,它会从IDLE状态过渡到BUSY状态。当承诺解析(SUCCESS)或拒绝(FAILURE)。3 秒后,它重置回 IDLE .

我正在尝试根据状态切换类名。但它不起作用,我不知道如何正确地做到这一点。我不确定我是否(以及如何)应该使用react-transition-group插件来顺利完成此操作,因为组件没有有条件地挂载/卸载。

也许我应该使用 css 动画而不是 css 过渡。这会是更好的方法吗?

这里活生生的例子:https://codesandbox.io/s/yjl5o5vr4v

这是我的代码:

SubmitButton.tsx

import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { IconProp } from '@fortawesome/fontawesome-svg-core'
import classNames from 'classnames'
import './SubmitButton.css'
// flag to switch whether dummy request should succeed or fail
let workSuccess = true
interface IProps {}
interface IState {
  status: 'IDLE' | 'BUSY' | 'SUCCESS' | 'FAILURE'
  label: string
  icon?: IconProp
}
const initialState: IState = {
  status: 'IDLE',
  label: 'Click',
  icon: undefined,
}
class SubmitButton extends React.PureComponent<IProps, IState> {
  public state: IState = { ...initialState }
  public render() {
    const { label, icon, status } = this.state
    return (
      <button className="SubmitButton" onClick={this.handleClick}>
        <span
          className={classNames({
            'animation--after': status === 'BUSY',
            'animation--before': status === 'SUCCESS' || status === 'FAILURE',
            ['animation']: status === 'IDLE',
          })}
        >
          {icon && (
            <FontAwesomeIcon className="SubmitButton__icon" icon={icon} />
          )}
          {label}
        </span>
      </button>
    )
  }
  private handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
    const { status } = this.state
    if (status === 'IDLE') {
      // animation: 'roll up' (out of view)
      // animation: reset position
      this.setState({
        label: 'Loading...',
        icon: 'spinner',
        status: 'BUSY',
      })
      // animation: 'roll up' (into view)
      try {
        const response = await this.doWork()
        // animation: 'roll up' (out of view)
        if (response) {
          // animation: reset position
          this.setState({
            label: 'OK',
            icon: 'check',
            status: 'SUCCESS',
          })
          // animation: 'roll up' (into view)
        }
      } catch (err) {
        // animation: reset position
        this.setState({
          label: 'ERROR',
          icon: 'exclamation',
          status: 'FAILURE',
        })
        // animation: 'roll up' (into view)
      } finally {
        // animation: reset position
        this.setState({ ...initialState })
        // animation: 'roll up' (into view)
      }
    }
  }
  private doWork = () => {
    return new Promise<boolean>((resolve: any, reject: any) => {
      setTimeout(() => {
        if (workSuccess) {
          resolve(true)
        } else {
          reject('An error happened...')
        }
        workSuccess = !workSuccess
      }, 3000)
    })
  }
}
export default SubmitButton

提交按钮.css

.SubmitButton {
  overflow: hidden;
  cursor: pointer;
  outline: none;
  font-size: 16px;
  padding: 12px 32px;
}
.SubmitButton__icon {
  margin-right: 12px;
}
.animation {
  display: inline-block;
  transition: transform 300ms ease-out;
  transform: translateY(0);
}
.animation--before {
  transition: transform 300ms ease-out;
  transform: translateY(50px);
}
.animation--after {
  transition: transform 300ms ease-out;
  transform: translateY(-50px);
}

您可以使用gif图像而不是FontAwesome图标。 请检查下面的代码。

目前我使用了低质量的 gif 作为目的,但您可以从您的项目中加载一个好的 gif。

 class SubmitButton extends React.PureComponent<IProps, IState> {
  public state: IState = { ...initialState };
  public render() {
    const { label, icon, status } = this.state;
    return (
      <>
        <button className="SubmitButton" onClick={this.handleClick}>
          <span
            className={classNames({
              "animation--after": status === "BUSY",
              "animation--before": status === "SUCCESS" || status === "FAILURE",
              ["animation"]: status === "IDLE"
            })}
          >
            {icon && (
              <img src="http://www.ajaxload.info/cache/FF/FF/FF/00/00/00/1-0.gif" />
            )}
            {label}
          </span>
        </button>
      </>
    );
  }

演示

相关内容

  • 没有找到相关文章

最新更新