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;

  

posted @ 2020-12-07 16:21  alisa.huang  阅读(216)  评论(0编辑  收藏  举报