# React 实现异步按钮

AsyncButton 组件实现思路:

  • 如果 onClick 事件是异步的 (返回 Promise),就需要 Loading 状态
  • 除了要处理 resolve 还别忘了处理 reject

# 例子:业务自行维护 Loading 状态

import { Button } from 'antd'
import { useState } from 'react';
import { login } from './services'

function Loading() {
  const [loading, setLoading] = useState(false)
  async function handleLogin() {
    setLoading(true)
    try {
      await login()
    } finally {
      setLoading(false)
    }
  }

  return (
    <div>
      <Button onClick={handleLogin} loading={loading}>Login</Button>
    </div>
  );
}

export default Loading;

# 例子:封装 AsyncButton 组件

import { Button } from 'antd'
import { useState } from 'react';

function AsyncButton({ onClick, children }) {
  const [loading, setLoading] = useState(false)
  async function handleClick() {
    setLoading(true)
    try {
      await onClick()
    } finally {
      setLoading(false)
    }
  }
  return <Button onClick={handleClick} loading={loading}>
    {children}
  </Button>
}

export default AsyncButton

# 例子:在列表页中使用 AsyncButton

import React from 'react'
import { Table } from 'antd'
import { getAllUsers, deleteUser } from './services'
import AsyncButton from './AsyncButton'

class ListDemo extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      users: [],
      loading: false
    }

    this.columns = [
      {
        title: 'Name',
        dataIndex: 'name',
        key: 'name',
        render: text => <a>{text}</a>,
      },
      {
        title: 'Age',
        dataIndex: 'age',
        key: 'age',
      },
      {
        title: 'Action',
        key: 'action',
        render: (text, record) => (
          <AsyncButton onClick={() => this.handleDeleteUser(record.id)}>Delete</AsyncButton>
        ),
      },
    ]
  }

  async componentDidMount() {
    await this.fetchData()
  }

  async fetchData() {
    this.setState({ loading: true })
    const users = await getAllUsers()
    this.setState({ users, loading: false })
  }

  async handleDeleteUser(id) {
    await deleteUser(id)
    this.fetchData()
  }

  render() {
    return <Table
      columns={this.columns}
      dataSource={this.state.users}
      loading={this.state.loading}
      rowKey="id"
    />
  }
}

export default ListDemo