RecyclerListView прокручивает вверх onEndReached с функциональным компонентом
Я реализовал RecyclerListView
(Flipkart Github) с использованием Redux, как показано ниже. Кажется, все работает отлично, кроме случаев, когдаonEndReached
вызывается и поступает новый пакет данных, список размещается вверху страницы, а не остается гладким. Посмотрите на это поведение в GIF ниже:
Примечание. Это происходит в Интернете (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);
2 ответа
Просто добавьте приведенную ниже строку кода после вашего
layoutProvider
.
shouldRefreshWithAnchoring
Свойство layoutProvider запрещает списку просмотра переработчика обновлять существующие строки, если в список добавлено больше строк.
layoutProvider.shouldRefreshWithAnchoring = false;
Решение здесь: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
}
)
)