javascript 反应无限滚动装饰组件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript 反应无限滚动装饰组件相关的知识,希望对你有一定的参考价值。

// React Infinite Scrolling Decorated Component

import React, { PropTypes } from 'react';
import _ from 'lodash';
import $ from 'jquery';

function getDisplayName(Component) {
  return Component.displayName || Component.name || 'Component';
}

export default function(options = {}) {
  const propName = options.propName;
  const modelName = options.modelName;

  if (!propName) {
    throw new Error('propName is required');
  }

  if (!modelName) {
    throw new Error('modelName is required');
  }

  return function(DecoratedComponent) {
    const displayName = 'InfiniteScrolling(' + getDisplayName(DecoratedComponent) + ')';

    return React.createClass({
      displayName: displayName,

      contextTypes: {
        store: PropTypes.object.isRequired
      },

      getInitialState: function() {
        return {
          pages: [
            this.props[propName]
          ]
        };
      },

      componentDidMount: function() {
        window.addEventListener('scroll', this.onPageScroll);
      },

      componentWillUnmount: function() {
        window.removeEventListener('scroll', this.onPageScroll);
      },

      onPageScroll() {
        const storeState = this.context.store.getState();
        const pages = this.state.pages;
        const firstPage = pages[0];
        const lastPage = pages[pages.length - 1];
        const nextPageNumber = Number(lastPage.query.pagination.page) + 1;
        const totalPage = firstPage.meta.totalPage;

        var isScrollAtBottom = (window.innerHeight + window.scrollY) == $(document).height();

        if (isScrollAtBottom && nextPageNumber <= totalPage) {
          this.onLoadMore();
        }
      },

      componentWillReceiveProps: function(nextProps) {
        const storeState = this.context.store.getState();
        const pages = this.state.pages;

        // Whenever the component re-renders, we need to rebuild our collection of pages
        // by fetching them back out of the Store. If we don't do this, our state data
        // will always be stale - we'll never know when data finishes being fetched, and
        // in the cases where some of the data is being modified, such as being updated
        // or deleted, we won't get a change to react to those changes and inform the user.
        let nextPages = pages.map(function(page) {
          const query = JSON.stringify(page.query);
          return storeState[modelName].find[query];
        });

        const currentQuery = JSON.stringify(this.props[propName].query.where);
        const nextQuery = JSON.stringify(nextProps[propName].query.where);

        if (currentQuery !== nextQuery) {
          nextPages = [
            nextProps[propName]
          ];
        }

        this.setState({
          pages: nextPages
        });
      },

      onLoadMore: function() {
        const storeState = this.context.store.getState();
        const pages = this.state.pages;
        const lastPage = pages[pages.length - 1];
        const nextPageNumber = Number(lastPage.query.pagination.page) + 1;
        const query = lastPage.query;

        // Build the next page's query from the previous page. The only
        // thing we're changing is the page of data we want to fetch
        const nextQuery = {
          where: query.where,
          pagination: _.defaults({
            page: nextPageNumber
          }, query.pagination)
        };

        // See if the next page has already been fetched, and used the cached page
        // if available
        let nextPage = storeState[modelName].find[JSON.stringify(nextQuery)];

        if (!nextPage) {
          // The 'find' action has a slightly different interface than the 'getState' call
          // in 'lore.connect'. When calling the 'find' action directly, you need to pass
          // in the 'where' clause and the 'pagination' information as different arguments,
          // like 'lore.actions.tweet.find(where, pagination)'
          nextPage = lore.actions[modelName].find(nextQuery.where, nextQuery.pagination).payload;
        }

        pages.push(nextPage);

        this.setState({
          pages: pages
        });
      },

      render: function() {
        return React.createElement(
          DecoratedComponent,
          _.assign({ref: 'decoratedComponent'}, this.state, this.props, { onLoadMore: this.onLoadMore })
        );
      }
    });
  }
};

以上是关于javascript 反应无限滚动装饰组件的主要内容,如果未能解决你的问题,请参考以下文章

检测天气用户是不是在反应js和javascript中滚动div的底部

具有动态高度的反应虚拟化无限滚动问题

反应本机列表页脚组件未显示(功能组件)

如何对 ngControl 用 @Self 装饰的反应性组件进行单元测试

避免在反应组件中无限重新渲染

如何从无限重新渲染中停止反应组件