ListView上拉加載下拉刷新

import { utils } from 'goblin';
import { ListView, Button, PullToRefresh } from 'antd-mobile';
import { NoDataPanel } from 'components';
import { connect } from 'dva';
import { encryptionEtcObuNumber, isNotEmptyStr } from 'utils/tool';
import { PAGE_SIZE } from 'configs/constants';
import { namespace } from '../model';

/**
 * 自定義body的包裹組件
 * 問題:爲啥將render裏面無數據邏輯移入此方法
 * 緣由:解決下拉刷新時,刷新提示一直顯示的issue
 */
function ListContainer(props) {
  const dataList = props.dataList || [];

  return (
    <div className="am-list-body my-body">
      {
        dataList.length > 0 ? props.children : <NoDataPanel>
          <p>
            暫時沒有任何數據
          </p>
        </NoDataPanel>
      }
    </div>
  );
}

@connect(state => state[namespace], dispatch => ({
  replaceObuOrder(data) {
    return dispatch({ type: `${namespace}/replaceObuOrder`, payload: { ...data, pageSize: PAGE_SIZE } });
  },
  fetchUpdateState(data) {
    return dispatch({ type: `${namespace}/fetchUpdateState`, payload: data });
  },
}))

class ReplaceObuOrder extends React.Component {
  constructor(props) {
    super(props);
    const dataSource = new ListView.DataSource({
      rowHasChanged: (row1, row2) => row1 !== row2,
    });

    this.state = {
      dataList: [],
      dataSource,
      useBodyScroll: true, // 使用html的body做爲滾動容器
      refreshing: true, // 是否顯示刷新狀態
      isLoading: true, // 是否在加載中
      hasMore: true, // 是否最後一頁數據
      preId: '', // 上一頁最後一條記錄Id
    };
  }

  componentDidMount() {
    utils.setTitle('訂單列表');

    // 修復當前頁面有滾動條,從下頁面回退到當前頁面,ios出現白屏
    if ('scrollRestoration' in window.history) {
      window.history.scrollRestoration = 'manual'; // 改成manual以後,就不會記錄滾動位置
    }

    const { replaceObuOrder } = this.props;
    replaceObuOrder();
  }

  /**
   * 描述:數據有變化時;或者數據未變化,可是state的dataList爲空時,更新state
   * 問題:(this.state.dataList.length < 1)爲了防止多個頁面共用一個model,
      從其餘頁面進入屢次進入該頁面,因爲數據未變化,出現數據不展現的狀況
   */
  componentWillReceiveProps({ obuOrder }) {
    const { dataSource } = this.state;

    if ((JSON.stringify(obuOrder) !== JSON.stringify(this.props.obuOrder))
    || (this.state.dataList.length < 1)) {
      const num = obuOrder.length;
      const newList = [...this.state.dataList, ...obuOrder];

      // eslint-disable-next-line
      this.setState({
        dataList: newList,
        preId: (num > 0) ? obuOrder[num - 1].id : '',
        dataSource: dataSource.cloneWithRows(newList),
        hasMore: obuOrder.length === PAGE_SIZE,
        isLoading: false,
      });
    }
  }

  /**
   * 下拉刷新
  */
  onRefresh = async () => {
    const { isLoading } = this.state;
    const { replaceObuOrder, fetchUpdateState } = this.props;

    // 避免下拉時重複發送相同請求
    if (isLoading) {
      return;
    }
    // 重置state
    this.setState({
      refreshing: true,
      isLoading: true,
      dataList: [],
      preId: '',
      hasMore: true,
    });
    await fetchUpdateState({
      obuOrder: [],
    });
    await replaceObuOrder();
    this.setState({ refreshing: false, isLoading: false });
  }

  /**
   * 上拉加載
  */
  onEndReached = async () => {
    const { hasMore, preId, isLoading } = this.state;
    const { replaceObuOrder } = this.props;

    if (!hasMore || isLoading) {
      // hasMore避免最後一頁時,重複請求數據
      // 避免上拉時重複發送相同請求
      return;
    }

    this.setState({ isLoading: true });
    await replaceObuOrder({ preId });
    this.setState({ isLoading: false });
  }

  getRowData = (data) => {
    // Number強制進行類型轉換,避免後端返回類型不一致
    const gray = (Number(data.statusOrder) === 4) ? 'gray' : '';

    return (<div className="replaceObuOrder-item">
      <div className="title">
        <font>{data.typeDes}</font>
        <span><font className={gray}>{data.statusOrderDesc}</font>{data.subStatusDesc}</span>
      </div>
      <div className="detail">
        <div>{data.vanNumber}</div>
        <p>{data.cardName}:{isNotEmptyStr(data.cardNo) && encryptionEtcObuNumber(data.cardNo)}</p>
        {isNotEmptyStr(data.deviceId) && <p>電子標籤號:{encryptionEtcObuNumber(data.deviceId)}</p>}
        {isNotEmptyStr(data.description) && <p>{data.description}</p>}
        {isNotEmptyStr(data.subDescription) && <p>{data.subDescription}</p>}
      </div>
      <div className="my-btn">
        {data.buttons && data.buttons.map(item => (<Button
          className="button"
          onClick={this.handleButton(data, item.id)}
        >
          {item.name}
        </Button>))}
      </div>
    </div>);
  }

  handleButton = (data, id) => async () => {
    const { fetchUpdateState, history } = this.props;

    await fetchUpdateState({
      selectedObuOrderItem: data,
    });
    if (Number(id) === 1) {
      history.push('detail?normalProcess=false');
    } else if (Number(id) === 4) {
      history.push('pay?normalProcess=false');
    } else if (Number(id) === 13) {
      history.push('receiveInfo?normalProcess=false');
    }
  }

  render() {
    const { dataSource, useBodyScroll, refreshing, dataList, isLoading } = this.state;

    return (
      <div className="replaceObuOrder">
        <ListView
          dataSource={dataSource}
          renderRow={rowData => this.getRowData(rowData)}
          pageSize={PAGE_SIZE}
          renderBodyComponent={() => <ListContainer dataList={dataList} />}
          pullToRefresh={<PullToRefresh
            distanceToRefresh={60}
            refreshing={refreshing}
            onRefresh={this.onRefresh}
          />}
          onEndReached={this.onEndReached}
          onEndReachedThreshold={50}
          useBodyScroll={useBodyScroll}
          renderFooter={
            () => (
              <div>
                {!isLoading && '已經沒有更多數據了'}
              </div>
            )
          }
        />
      </div>
    );
  }
}

export default ReplaceObuOrder;
相關文章
相關標籤/搜索