0.0.5 • Published 4 years ago

@ekit/async v0.0.5

Weekly downloads
76
License
MIT
Repository
github
Last release
4 years ago

name: Async menu: 'Components'

route: /ekit/async

import { Props, Playground } from 'docz'; import Async from './src/Async.tsx'; import Example, { StatusFaker, FormCoreFaker, ModalFaker, FormFaker, ResultTypeFaker, AsyncFaker, AsyncConfirmedFaker, } from './tests/Example.tsx';

Async

Tkit 异步操作工具模块、组件。

npm i -S @ekit/async

2. 配置 Async 组件

在最顶层组件内引入 Async,监听并处理 Async 事件。

import Async from '@ekit/async';

- 2.1 Async Props

Async 组件 Props 类型是 AsyncProps

AsyncProps 接口

AsyncProps 接口包含以下属性和方法:

示例

首先在 Root.tsx 内引入 Async。

import React from 'react';
import { Spin, Modal, message } from 'antd';
import Async from '@ekit/async';

// 请在 Root.tsx 内添加
<Async
  form={Form}
  // loading={arg => <Spin spinning={arg.status.isFetch} />}
  sharedLoading={Spin}
  modal={Modal}
  tips={({ type, message: msg }) => message[type](msg)}
/>;

- 2.1.①. Async Form

表单组件,用来渲染表单,并在 Modal.onOk 时提交表单。表单组件 Props 的类型是 AsyncFormProps,实现了 AsyncForm 定义。

class Form extends React.Component<AsyncFormProps> implements AsyncForm {}

AsyncFormProps 接口

AsyncFormProps 包含以下属性和方法:

AsyncForm 接口

AsyncForm 包含以下属性和方法:

示例

实现一个 FakeForm 组件:

export class FakeForm extends React.Component<AsyncFormProps> implements AsyncForm {
  public static fakeData = {
    name: 'skipper',
  };
  public constructor(props: AsyncFormProps) {
    super(props);
    if (props.getForm) {
      props.getForm(this);
    }
  }
  public submit() {
    return FormFaker.fakeData;
  }
  public render() {
    return <div>nihao</div>;
  }
}

- 2.1.②. Deprecated loading

【废弃,用 sharedLoading 替代】显示加载效果的组件

  interface loading {
    (arg: AsyncStatus) => any;
  }

AsyncStatus 接口

AsyncStatus 包含以下属性和方法:

示例:

(arg: AsyncStatus) => <Spin spinning={arg.status.isFetch} />;

- 2.1.③. sharedLoading

配置所有 effect 共用的全局加载效果组件。

示例

简单的全局加载效果组件:

() => 'loading';

- 2.1.④. modal 属性

弹窗组件,可直接使用 Antd Modal 或自定义,Modal 组件 Props 类型为 AsyncModalProps

class Modal extends React.Component<AsyncModalProps> {}

AsyncModalProps 接口

AsyncModalProps 包含以下属性和方法:

示例

实现一个 FakeModal:

export class FakeModal: extends React.Component<AsyncModalProps> {
  public render() {
    const { visible, title, content, className, confirmLoading, onOk, onCancel } = this.props;
    return <div>{content}</div>;
  }
}

- 2.1.⑤. tips

配置全局的成功、错误提示函数,该函数接收的参数类型为 AsyncResultEventType

interface tips {
  (msg: AsyncResultEventType) => void;
}

AsyncResultEventType 接口

AsyncResultEventType 包含以下属性和方法:

示例

实现一个 message 提示函数:

 const message = { error: () => 0, success: () => 1 }
 ({ type, message: msg }: AsyncResultEventType) => message[type](msg);

3. API

Async 也提供了点击取消按钮时候,同时取消异步请求的接口。

import { doAsync, doAsyncConfirmed, useAsyncStatus } from '@ekit/async';

- 3.1. doAsync

doAsync 出发一个可取消的异步事件。

- 3.1.① doAsync 参数

IAsyncActionProps 接口

示例

doAsync(<IAsyncActionProps<any>>{ ... })

取消示例

import { promiseFactory } from '@ekit/ajax';

const [{ resolve }, cancel] = promiseFactory<string>();
const res = yield doAsync({
  fetch: naotu.doModifyDoc,
  ...,
  paramsGenerator: ({ extraParams }) => [
    {
      doc: {
        ...extraParams
      }
    },
    {
      cancel
    }
  ],
  onCancel: () => {
    resolve('放弃了');
  },
  ...
});

- 3.2. doAsyncConfirmed

- 3.2.① doAsyncConfirmed 参数

IAsyncConfirmedParams 接口

示例

doAsyncConfirmed(<IAsyncConfirmedParams<any>>{ ... })

- 3.3. useAsyncStatus

我们可以通过 @ekit/async 提供的 useAsyncStatus Hooks,定制组件局部的 loading 效果。需要再容器内局部显示 loading 效果的,请勿给对应的 Model Effect 添加 loading 配置,否则也会显示全局 loading 效果。

示例

import { useAsyncStatus } from '@ekit/async';

const Cp = () => {
  const [status] = useAsyncStatus(
    (status: AsyncStatus) => status.effectName === 'docModel/getDocList'
  );

  return status ? 'loading' : null;
};

4. Demo

Demo 源码

import React from 'react';
import { Spin, Modal, Button, Input, message } from 'antd';
import { AjaxPromise, TkitAjaxFunction } from '@ekit/ajax';
import { AsyncResultEventType, doAsync, doAsyncConfirmed, Async } from '@ekit/async';

// @IMP: 表单组件
export class FormFaker extends React.Component<AsyncFormProps> {
  public static fakeData = {
    name: 'skipper',
  };
  public constructor(props: AsyncFormProps) {
    super(props);
    if (props.getForm) {
      props.getForm(this);
    }
  }
  public submit() {
    return FormFaker.fakeData;
  }
  public render() {
    return <div>nihao</div>;
  }
}

const loadData = (id: number): AjaxPromise<any> => {
  console.log('running effect');
  return new Promise((rs, rj) => {
    setTimeout(() => rs({ code: 0, message: '逗我呢', result: { id } }), 1000);
  });
};

export default function Example() {
  return (
    <div>
      <Async
        form={FormFaker}
        loading={(arg) => <Spin spinning={arg.status.isFetch} />}
        modal={Modal}
        tips={({ type, message: msg }) => message[type](msg)}
      />
      <Button
        onClick={() => {
          doAsync({
            fetch: loadData,
            callback: console.log,
            modalProps: {
              title: 'nihao',
              content: (
                <div>
                  <Input />
                  <Button
                    onClick={() => {
                      doAsync({
                        fetch: loadData,
                        modalProps: {
                          content: '你好',
                          title: '2',
                        },
                      });
                    }}
                  >
                    嵌套了
                  </Button>
                </div>
              ),
            },
          });
        }}
      >
        弹窗测试
      </Button>
      &nbsp;
      <Button
        onClick={() => {
          doAsyncConfirmed({
            fetch: loadData,
            callback: console.log,
          });
        }}
      >
        不弹窗带loading测试
      </Button>
      &nbsp;
      <Button
        onClick={() => {
          doAsyncConfirmed({
            fetch: loadData,
            callback: console.log,
            indicator: null,
          });
        }}
      >
        不显示loading测试
      </Button>
    </div>
  );
}