antd Moblie 中hooks listView长列表使用方法,二次进入报错dataSource报错 must be the same

764 阅读3分钟
官方使用方法(自定义容器)  https://mobile.ant.design/components/list-view-cn/#components-list-view-demo-basic-sticky

官方的使用方法出看一眼用着很顺,但是一放上数据就会出现一些意想不到的问题。本人深有体会

一些小伙伴看第一眼有可能看不明白官方渲染的sectionIDs,rowIDs,dataBlobs是什么意思,其实也不用理解是什么意思,只要咱们自己的数据和官方创建的key对应上就没有问题了。 具体怎么对应呢?

此解说与1相互对应:

将 NUM_SECTIONS 改为你每一也获取的数据条数,我每一页获取10条  我就将5改为10,
如果10条足够你充满一整页那就将 NUM_ROWS_PER_SECTION 改为1,我足够充满一整页我就改为1,
改完这些之后我们就不用关心组件自动生成key的问题了,我们只要将数据整合到一起就可以了,如何整合数据请看2
将官网中的pageSize={4}  改为咱们的10 

1、下面是官方使用方法和更改配置的方法:

const NUM_SECTIONS = 5;  //每一页的条数
const NUM_ROWS_PER_SECTION = 5;  //渲染几次  为什么要渲染多次呢,因为如果首次加载的时候不足一页那么下拉就不会触发加载数据。
let pageIndex = 0;

const dataBlobs = {};
let sectionIDs = [];
let rowIDs = [];
function genData(pIndex = 0) {
    for (let i = 0; i < NUM_SECTIONS; i++) {
    const ii = (pIndex * NUM_SECTIONS) + i;
    const sectionName = `Section ${ii}`;
    sectionIDs.push(sectionName);
    dataBlobs[sectionName] = sectionName;
    rowIDs[ii] = [];

    for (let jj = 0; jj < NUM_ROWS_PER_SECTION; jj++) {
      const rowName = `S${ii}, R${jj}`;
      rowIDs[ii].push(rowName);
      dataBlobs[rowName] = rowName;
    }
  }
  sectionIDs = [...sectionIDs];
  rowIDs = [...rowIDs];
}

2、我将官方的类组件改成hooks组件

const [dataSourceAll, setdataSourceAll] = useState([]);  //存储最近一次获取的数据,为了后面判断是否需要继续请求数据。如果长度是0时就停止请求数据
const [dataSourcenew, setdataSourcenew] = useState([]);   //存储原有的数据和新的数据做合并。
const getList=()=>{
     let dataSources=[]  //新获取到的数据
     setdataSourceAll(dataSources);  //将新请求到的数据放入
     setdataSourcenew([...dataSourcenew, ...dataSources])  //将新的数据和与原有的数据合并到一起。
}
useEffect(()=>{
      getList()  //获取数据
},[])
// 此方法为下拉获取数据
const onEndReached = async (event) => {
    // 在此处判断当获取的数据里面是否有数据,如果没有证明到了最后一页,则不去获取数据。
    if (dataSourceAll.length > 0) {
        getList()  //获取数据
        // 每获取一次数据的时候都要在原key的基础上面增加
        setdataSource(dataSource.cloneWithRowsAndSections(dataBlobs, sectionIDs, rowIDs))
        // 调用增加key的方(增加key指的则是官方中genData(方法))
        // 在官方中是先调用getData方法,但是因为异步的问题我们要后调用genData方法。
        genData(++pageIndex);
    }
}

好了 现在数据已经整理好了那么如何渲染出来呢?

在官网中的data是官网中模拟的静态数据,我们只需要将静态数据替换成我们自己整合成功之后的数据替换里面的data(data指的就是官网中的静态数据),因为我们在2中已经通过setdataSourcenew([...dataSourcenew, ...dataSources]) 将数据整合到了一起,那么现在将data替换成dataSourcenew就可以了。

//官网:
let index = data.length - 1;
//替换后:
let index = dataSourcenew.length - 1;
const row = (rowData, sectionID, rowID) => {
  if (index < 0) {
    //官网:
    index = data.length - 1;
    //替换后:
    index = dataSourcenew.length - 1;
  }
  //官网:
  const obj = data[index--];
  //替换后:
  const obj = dataSourcenew[index--];
  return (
    <div key={rowID} style={{ padding: '0 15px' }}>
      <div
        style={{
          lineHeight: '50px',
          color: '#888',
          fontSize: 18,
          borderBottom: '1px solid #F6F6F6',
        }}
      >{obj.title}</div>
      <div style={{ display: '-webkit-box', display: 'flex', padding: '15px 0' }}>
        <img style={{ height: '64px', marginRight: '15px' }} src={obj.img} alt="" />
        <div style={{ lineHeight: 1 }}>
          <div style={{ marginBottom: '8px', fontWeight: 'bold' }}>{obj.des}</div>
          <div><span style={{ fontSize: '30px', color: '#FF6E27' }}>35</span>¥ {rowID}</div>
        </div>
      </div>
    </div>
  );
};

现在已经将数据都渲染进怎们的dom里面了,但是如果切换页面的话会出现 must be the same的字样,原因是因为咱们在外部定义了初始值

let pageIndex = 0;
const dataBlobs = {};
let sectionIDs = [];
let rowIDs = [];

我们只需要将这四个初始值重置一下就可以了 下面是hooks手动重置初始值的方法

useEffect(() => {
    // 手动将字段重置,防止二次进入页面的时候渲染key的时候出错。
    return () => {
        page = 0;
        pageIndex = 0;
        sectionIDs = [];
        rowIDs = [];
    }
}, [])