【问题标题】:Firebase infinite scroll proper solution?Firebase无限滚动正确的解决方案?
【发布时间】:2019-06-26 08:35:58
【问题描述】:

我在一个组件中构建了一个非常复杂的列表,所有查询都以相同的方式进行。当我到达列表的末尾时,我将获取限制增加了 10... 一切都很顺利,直到我意识到我正在重新加载所有数据(不仅仅是新的 10 个)。我想避免所有这些读取以降低成本-我不确定firebase是否会忽略已加载的数据...当我每次获取额外的 10 个时,我的列表运行得非常顺利,但我不知道是否幕后的事情会回来困扰我!

更新

我根据一些有用的反馈更新了我的代码,我相信我的工作应该是这样的。我只关心一件事。当我在第一次获取后到达列表底部时,我会将所有以前的数据传递给我的动作创建者,然后将其连接到新获取的数据。随着列表的增长,每次我触底时都会重复这种情况。我的列表将有超过 1000 条记录,所以我担心潜在的性能问题,应该这样吗?在下面看看我的新尝试!

最初的尝试:

onEndReached = () => {
 const { searchFilterText, effectVal } = this.state;

   this.setState({
     strainFetchIndex: this.state.strainFetchIndex + 10
   }, () => {
     const offset = this.state.strainFetchIndex;

      if (searchFilterText === '') {
       this.props.strainsFetch(offset);
     } else if (searchFilterText === 'Hybrid' || searchFilterText === 'Salt' || searchFilterText === 'Initial') {
       this.props.filterStrainAction(searchFilterText, offset);
     } else if (searchFilterText === 'Effects') {
       this.props.filterByEffect(effectVal, offset);
     }
  });
}

//HERES 1 of 4 ACTION CREATORS WHERE I FETCH MORE DATA (ALL ARE SIMILAR)

    export const strainsFetch = (offset) => {
      const ting = offset || 1;
        return (dispatch) => {
          firebase.database().ref('/strains')
            .orderByKey()
            .limitToFirst(1 * ting)
            .on('value', snapshot => {
              dispatch({ type: STRAINS_FETCH_SUCCESS, payload: snapshot.val() });
            });
        };
      };

新尝试:

  onEndReached = () => {
    const { searchFilterText } = this.state;
    const { lastKey } = this.props;
    const currentStrains = this.props.strains;

      if (this.state.filterLabel === 'Favourites') {
        return null;
      }
      if (searchFilterText === '') {
        //here I pass all previous records along with the last key (last key comes from my action creator)
        this.props.strainsFetch(currentStrains, lastKey);
      } 
    }



    //ACTION CREATOR



    export const strainsFetch = (currentStrains, lastKey) => {
      if (!lastKey) {
        return (dispatch) => {
          // console.log('first Fetch');
          firebase.database().ref('/strains')
            .orderByKey()
            .limitToFirst(10)
            .on('value', snapshot => {
              const snap = snapshot.val();
              const snapKeys = Object.keys(snap);
              const createLastKey = snapKeys[9];

              dispatch({ type: STRAINS_FETCH_SUCCESS, payload: snapshot.val(), key: createLastKey });
            });
        };
      }
        return (dispatch) => {
          // console.log('subsequent Fetch');
          firebase.database().ref('/strains')
            .orderByKey()
            .startAt(`${lastKey}`)
            .limitToFirst(11)
            .on('value', snapshot => {
              const snap = snapshot.val();
              const snapKeys = Object.keys(snap)
              .slice(1);

              const results = snapKeys
                 .map((key) => snapshot.val()[key]);

              const createLastKey = snapKeys[snapKeys.length - 1];
              const concatStrains = _.concat(currentStrains, results);

              dispatch({ type: STRAINS_FETCH_SUCCESS, payload: concatStrains, key: createLastKey });
            });
        };
      };



      //HERE IS WHAT MY REDUCER LOOKS LIKE



    import {
      STRAINS_FETCH_SUCCESS
    } from '../actions/types';

    const INITIAL_STATE = {};

    export default (state = INITIAL_STATE, action) => {
      switch (action.type) {
        case STRAINS_FETCH_SUCCESS:
        // console.log(action.payload);
          return { strains: action.payload, lastKey: action.key };

        default:
          return state;
      }
    };

随着列表的不断增长,一遍又一遍地将以前的数据传递给我的操作创建者,这是一种不好的做法吗?或者有没有更有效的方法来做到这一点?

谢谢大家!

干杯。

【问题讨论】:

  • 您需要提供偏移量。您的第一次调用将在获取期间获取项目 0-10 - 后续请求将传递从第十个文档开始的 ?offset=10
  • 嗨勒克斯,恐怕我不明白你想说什么。每次我的列表到达末尾时,我都会传入一个偏移量。每次加载比以前多 10 个项目时,它将偏移量增加 10。 @lux
  • 用 Firebase 无限滚动是戏剧性的,因为需要以相反的顺序附加。例如:apps-script-community-ar-a9405.firebaseapp.com(注意右上角的数字)。如果我没记错的话,在随后的请求中,必须获取 10+1,但跳过 1。
  • 谢谢马丁,你是对的......让它正常工作似乎很麻烦......你如何建议我得到最后一个钥匙作为我下一个起点获取?

标签: reactjs firebase firebase-realtime-database


【解决方案1】:

您是正确的,因为除了新的之外,您还重新加载了所有旧的。如果你只想加载新的,那么你应该使用.startAt()方法,查看relevant docs here

您的最终设置如下所示:

export const strainsFetch = (offset) => {
    const startingIndex = offset || 1;
    const numRecordsToLoad = 10;
    return (dispatch) => {
        firebase.database().ref('/strains')
            .orderByKey()
            .startAt(startingIndex)
            .limitToFirst(numRecordsToLoad)
            .on('value', snapshot => {
                dispatch({ type: STRAINS_FETCH_SUCCESS, payload: snapshot.val() });
            });
    };
};

【讨论】:

  • 您好 Jeremy,感谢您确认。不过,我使用的是实时数据库,而不是链接引导我的云 Firestore。我还能做到吗?
  • @hugger 哎呀!很抱歉,here is the link for RTD.startAt() 的文档应该是一样的。
  • 感谢杰里米! start at 将是最后一项的关键,对吗?如果是这样,你会如何推荐我得到这个值?我一直在做一些研究,如果没有这么多的代码,似乎没有明确的解决方案可以实现这一目标!!如果只针对一个查询,我不介意,但我有很多......对我来说似乎很疯狂,没有一种更有效的方法来实现这样的分页。
  • @hugger 是的,startAt 将是最后一项的关键。密钥包含在您下拉的快照中,this question 的答案显示了 RTD 和 Firestore 的方式 - 您只需将密钥包含在操作的有效负载中,而不仅仅是 snapshot.val(),并拥有您的减速器处理将其与该值的其余信息一起放入商店。根据您的商店结构,这可能需要对商店结构进行一些修改
  • 嘿@JeremyW!非常感谢帮忙。我认为我的工作正常,无需使用startAt() 一遍又一遍地加载所有数据,我只关心一件事......我已经用我的新尝试更新了我的问题,介意检查一下吗?跨度>
猜你喜欢
  • 2017-08-08
  • 1970-01-01
  • 2018-06-29
  • 1970-01-01
  • 1970-01-01
  • 2015-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多