4

我已经使用 Redux 实现了一个RecyclerListViewFlipkart Github),如下所示。一切似乎都运行良好,除非当onEndReached被调用并且新一批数据通过时,列表被定位到页面顶部而不是保持平滑。在下面的 GIF 中查看该行为:

注意:这发生在 web(chrome) 上。我尝试了最新的稳定版和 2.0.13-alpha.1

import React, { useCallback } from 'react';
import { View, Text, Dimensions } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import { RecyclerListView, DataProvider, LayoutProvider } from 'recyclerlistview/web';
import { createSelector } from 'reselect';

import { loadData } from '../actions';

const selectData = createSelector(
  state => state.data,
  data => Object.values(data),
);

let containerCount = 0;
class CellContainer extends React.Component {
  constructor(args) {
    super(args);
    this._containerId = containerCount++;
  }
  render() {
    return (
      <View {...this.props}>
        {this.props.children}
        <Text>Cell Id: {this._containerId}</Text>
      </View>
    );
  }
}

const List = ({ isServer }) => {
  let { width } = Dimensions.get('window');

  const dispatch = useDispatch();

  const data = useSelector(selectData);

  const dataDataProvider = new DataProvider((r1, r2) => {
    return r1 !== r2;
  }).cloneWithRows(data);

  const onEndReached = useCallback(() => dispatch(loadData()), [dispatch]);

  const layoutProvider = new LayoutProvider(
    () => 0,
    (type, dim) => {
      dim.width = width;
      dim.height = 240;
    },
  );

  const rowRenderer = (type, data) => {
    return <CellContainer />;
  };

  return (
    <View
      style={{
        display: "flex",
        flex: 1,
        width: "100vw",
        height: "100vh"
      }}
    >
      <RecyclerListView
        layoutProvider={layoutProvider}
        dataProvider={dataDataProvider}
        onEndReached={onEndReached}
        rowRenderer={rowRenderer}
      />
    </View>
  );
};

export default List;

更新:我可以确认基于类的版本使用 redux connect 没有问题。倾向于这是与图书馆的某种不兼容。不过很有趣。

下面的代码片段是这个演示的简化工作示例https://codesandbox.io/s/k54j2zx977

class App extends React.Component {
  constructor(props) {
    let { width } = Dimensions.get('window');

    super(props);
    this.state = {
      dataProvider: new DataProvider((r1, r2) => {
        return r1 !== r2;
      }),
      layoutProvider: new LayoutProvider(
        index => 0,
        (type, dim) => {
          dim.width = width;
          dim.height = 240;
        },
      ),
      count: 0,
    };
  }

  componentDidUpdate(prevProps) {
    if (this.props.data.length !== prevProps.data.length) {
      this.setState({
        dataProvider: this.state.dataProvider.cloneWithRows(this.props.data),
        count: this.props.data.length
      });
    }
  }

  componentWillMount() {
    this.props.loadData();
  }

  async fetchMoreData() {
    this.props.loadData();
  }

  rowRenderer = (type, data) => {
    //We have only one view type so not checks are needed here
    return <CellContainer />;
  };

  handleListEnd = () => {
    this.fetchMoreData();
    //This is necessary to ensure that activity indicator inside footer gets rendered. This is required given the implementation I have done in this sample
    this.setState({});
  };

  render() {
    //Only render RLV once you have the data
    return (
      <View style={styles.container}>
        {this.state.count > 0 ? (
        <RecyclerListView
          style={{ flex: 1 }}
          contentContainerStyle={{ margin: 3 }}
          onEndReached={this.handleListEnd}
          dataProvider={this.state.dataProvider}
          layoutProvider={this.state.layoutProvider}
          renderAheadOffset={0}
          rowRenderer={this.rowRenderer}
        />
        ) : null}
      </View>
    );
  }
}

export default connect(
  state => ({
    data: selectData(state),
  }),
  dispatch => bindActionCreators({ loadData }, dispatch),
)(App);
4

2 回答 2

2

只需在您的layoutProvider. shouldRefreshWithAnchoring如果将更多行添加到列表中,则 layoutProvider的属性可防止回收器视图列表不刷新现有行。

layoutProvider.shouldRefreshWithAnchoring = false;
于 2021-12-13T10:37:44.900 回答
0

解决方案在这里: https ://github.com/Flipkart/recyclerlistview/issues/449

只需添加

  const [layoutProvider] = React.useState(
new LayoutProvider(
  (index) => 1,
  (type, dim) => {
    dim.width = ITEM_HEIGHT
    dim.height = ITEM_HEIGHT
  }
)

)

于 2020-12-01T04:23:38.373 回答