RN uses RecyclerListView to implement public list components-records

import React, { useState, useEffect, useRef } from "react";
import { View, Text, RefreshControl, StyleSheet } from "react-native";
import { RecyclerListView, DataProvider, LayoutProvider } from "recyclerlistview";
import { APIManager, NetCode, ReqType } from "../../api/APIManager";
import { Toast } from "@ant-design/react-native";
import StickyContainer from "recyclerlistview/dist/web/core/StickyContainer";

/**
 * item类型
 * @type {
   
   {Item: number, Header: number}}
 */
const RecycleItemType = {
  Header: 0,
  Item: 1,
};

/**
 * 头部模块参数
 * @constructor
 */
function ListHeaderFunc() {
  this.width = 0;
  this.height = 0;
  this.component = null;
}

/**
 * 吸顶模块参数
 * @constructor
 */
function StickyHeaderFunc() {
  this.stickyHeaderIndices = [];
  this.stickyFooterIndices = [];
  this.component = null;
}

const CustomRecyclerListView = ({
                                  apiName,
                                  params,
                                  width,
                                  height,
                                  requestType,
                                  ListHeader = new ListHeaderFunc(),
                                  ListItem,
                                  ListFooter,
                                  StickyHeader = new StickyHeaderFunc(),
                                  ...props
                                }) => {
  /*-------------------------生命周期----------------------------*/
  useEffect(() => {
    onRefresh();
  }, []);
  /*-------------------------数据----------------------------*/
  const recyclerRef = useRef(null);
  const [dataProvider] = useState(new DataProvider((r1, r2) => r1 !== r2));
  const [listData, setListData] = useState({
    page: 1,
    size: 10,
    list: [],
  });
  const [loadFinish, setLoadFinish] = useState(true);//是否加载完所有数据
  const [refresh, setRefresh] = useState(true);//是否再刷新
  /*-------------------------API----------------------------*/
  /**
   * api请求
   * @param api_name
   * @param params
   */
  const fetchData = (api_name, params) => {
    new APIManager().netFetch(api_name, params, requestType)
      .done(result => {
        setRefresh(false);
        if (result.code === NetCode.NET_SUCCESS) {
          const { data } = result;
          fetchSuccess(params, data);
        } else {
          Toast.info(result.msg);
        }
      }, error => {
        setRefresh(false);
        console.log(error);
      });
  };
  /*-------------------------事件----------------------------*/
  /**
   * 解析请求成功
   * @param params
   * @param data
   */
  const fetchSuccess = (params, data) => {
    const { total } = data;
    let newList = [...listData.list];
    if (params.page === 1) {
      newList = data.data;
    } else {
      newList = newList.concat(data.data);
    }
    setLoadFinish(newList.length >= total);
    setListData({
      list: newList,
    });
  };

  /**
   * 下拉刷新
   */
  const onRefresh = () => {
    setRefresh(true);
    setListData({
      page: 1,
    });
    getData();
  };

  /**
   * 下拉加载
   */
  const onLoadMore = () => {
    setRefresh(true);
    setListData({
      page: listData.page + 1,
    });
    getData();
  };

  /**
   * 请求数据
   */
  const getData = () => {
    let param = {
      ...params,
      page: listData.page,
      size: listData.size,
    };
    fetchData(apiName, param);
  };
  /*-------------------------事件----------------------------*/

  /**
   * 设置布局
   * @type {LayoutProvider}
   */
  const layoutProvider = new LayoutProvider(
    (index) => {
      if (index === 0) {
        return RecycleItemType.Header;
      } else {
        return RecycleItemType.Item;
      }
    },
    (type, dim) => {
      if (type === RecycleItemType.Header) {
        dim.width = ListHeader.width; // 头部项的宽度
        dim.height = ListHeader.height + height; // 头部项的高度
      } else {
        dim.width = width; // 项的宽度
        dim.height = height; // 项的高度
      }
    },
  );

  /**
   * 返回列表项
   * @param type
   * @param data
   * @param index
   * @returns {JSX.Element}
   */
  const renderRow = (type, data, index) => {
    if (index === 0 && ListHeader.component) {
      return (
        <>
          {ListHeader.component}
          <ListItem item={data} />
        </>
      );
    }
    return (
      <ListItem item={data} />
    );
  };

  /**
   * 列表尾部视图
   * @returns {JSX.Element}
   */
  const renderFooter = () => {
    const { showFooter = true, ListFooter } = props;
    if (ListFooter !== undefined) {
      return (<ListFooter />);
    }
    if (!showFooter || !loadFinish) {
      return <View />;
    }
    return (
      <View
        style={styles.footerStyle}
      >
        <Text>没有更多了</Text>
      </View>
    );
  };

  const overrideRowRenderer = (type, data, index) => {
    const view = renderRow(type, data, index);
    switch (index) {
      case 7:
        const color = "cyan";
        return (
          <View style={
   
   { height: 100, backgroundColor: color, alignItems: "center", justifyContent: "center" }}>
            <Text style={
   
   { fontSize: 32 }}>Overridden sticky</Text>
          </View>
        );
      default:
        return view;
    }
  };

  /**
   * 列表
   * @returns {JSX.Element}
   * @constructor
   */
  const ListView = () => {
    return (
      <RecyclerListView
        ref={recyclerRef}
        scrollViewProps={
   
   {
          refreshControl: (
            <RefreshControl
              refreshing={refresh}
              onRefresh={onRefresh}
            />
          ),
        }}
        onEndReached={onLoadMore}
        layoutProvider={layoutProvider}
        dataProvider={dataProvider.cloneWithRows(listData.list)}
        rowRenderer={renderRow}
        renderFooter={renderFooter}
      />
    );
  };
  /*-------------------------主视图----------------------------*/
  if (StickyHeader) {
    return (
      <StickyContainer
        stickyHeaderIndices={StickyHeader.stickyHeaderIndices}
        stickyFooterIndices={StickyHeader.stickyFooterIndices}
        overrideRowRenderer={overrideRowRenderer}>
        <ListView />
      </StickyContainer>
    );
  }
  return (
    <ListView />
  );
};

export default CustomRecyclerListView;

const styles = StyleSheet.create({
  footerStyle: {
    alignItems: "center",
    justifyContent: "center",
    height: 40,
  },
  footerTextStyle: {
    fontSize: 14,
    color: "#999999",
  },
});

Guess you like

Origin blog.csdn.net/qq_41878758/article/details/132745914