When we setup the flatlist with hasmoreitems and pagination we seem to be experiencing an odd loading behaviour on scroll. If the cursor is outside the region of the flatlist and you scroll all the way to the bottom of the list no event is triggered to load more items. This may be a totally separate issue but we do not know why this is happening. However, when you scroll inside the region of the flatlist it seems like the hasmoreitems fires on every scroll event loading more items to the list each time.
this.state = {
hasMoreItems: false,
}
getUsersProfilesList = async () => {
return await client.service("users").find({
query: {
$limit: 10,
$skip: this.state.profiles.length,
}
}).then((profilesPage) => {
this.setState(prevState => ({
hasMoreItems: profilesPage.data.length === profilesPage.limit,
profiles: [...prevState.profiles, ...profilesPage.data],
loading: false
}))
})
}
render() {
<FlatList
list={this.state.profiles}
renderItem={this.renderUserProfile}
renderWhenEmpty={() => <div style={{ flex: 1, textAlign: "center" }}>List is empty!</div>}
hasMoreItems={this.state.hasMoreItems}
loadMoreItems={this.getUsersProfilesList}
/>
}
import React, { Component } from "react";
import Dropdown from 'react-dropdown';
import 'react-dropdown/style.css';
import FlatList from 'flatlist-react';
import UserProfileComponent from "../components/UserProfileComponent";
import UserFlaggedPost from "../components/UserFlaggedPost";
import moment from 'moment';
const feathers = require('@feathersjs/feathers');
const socketio = require('@feathersjs/socketio-client');
const authentication = require('@feathersjs/authentication-client');
const io = require('socket.io-client');
const socket = io("https://dev.mysite.com", {
transports: ['websocket'],
upgrade: false,
});
// Initialize our Feathers client application through Socket.io
// with hooks and authentication.
const client = feathers();
client.configure(socketio(socket));
client.configure(authentication({
storage: localStorage
}))
const options = [];
class User extends Component {
constructor(props) {
super(props)
this.state = {
hasMoreItems: false,
offset: 0,
loading: true,
profiles: [],
value: 1,
usersFlagged: [ ],
};
this.defaultOption = "Select date...";
for (let i = 0; i < 13; i++) {
if (i !== 12) {
options.push({
value: i,
label: moment().subtract(i, "month").startOf("month").format('MMM') + '-' + moment().subtract(i - 1, "month").startOf("month").format('MMM') + ' ' + moment().subtract(i, "month").year()
});
} else {
options.push({
value: i,
label: "None"
});
}
}
}
async componentDidMount() {
await client.authenticate({
strategy: "local",
uname: '...',
pword: '...',
extraProps: {
// tells the server what functionality the client's app version supports
apiVersion: '2',
},
});
await this.getUsersProfilesList();
}
renderUserProfile = (item, idx) => {
return (
<UserProfileComponent key={idx} item={item} />
);
}
renderUserFlaggedPost = (item, idx) => {
return (
<UserFlaggedPost key={idx} item={item} />
);
}
getUsersProfilesList = async () => {
//console.log("******************************* before skip: " + this.state.profiles.length + ", this.hasMoreItems=" + this.state.hasMoreItems)
return await client.service("users").find({
query: {
$limit: 10,
$skip: this.state.profiles.length,
}
}).then((profilesPage) => {
this.setState(prevState => ({
hasMoreItems: profilesPage.data.length === profilesPage.limit,
profiles: [...prevState.profiles, ...profilesPage.data],
loading: false
}))
//console.log("******************************* AFTER this.state.profiles.length: " + this.state.profiles.length + ", returned skip: " + profilesPage.skip + ", this.hasMoreItems=" + this.state.hasMoreItems)
})
.catch(error => console.log(error.message));
}
getUsersProfilesByMonth = async (start, end) => {
this.setState({ profiles: [] })
return await client.service("users").find({
query: {
createdAt: {
$lte: end,
$gte: start,
},
$limit: 10,
$skip: this.state.profiles.length,
}
}).then((profilesData) => {
this.setState(prevState => ({
hasMoreItems: profilesData.data.length === profilesData.limit,
profiles: [...prevState.profiles, ...profilesData.data],
loading: false
}))
})
}
searchByMonth = async (option) => {
let timeStart = 0;
let timeEnd = 0;
for (let i = 0; i < 13; i++) {
if (option.value === i) {
if (i !== 12) {
this.defaultOption = option.label;
timeStart = moment().subtract(i, 'months').startOf('month').valueOf();
timeEnd = moment().subtract(i, 'months').endOf('month').valueOf();
//console.log ("timeStart = " + moment().subtract(i, 'months').startOf('month').format("YYYY-MM-DD"));
//console.log ("timeEnd = " + moment().subtract(i, 'months').endOf('month').format("YYYY-MM-DD"));
await this.getUsersProfilesByMonth(timeStart, timeEnd);
} else {
await this.setState({ profiles: [] })
await this.getUsersProfilesList();
this.defaultOption = "Select date...";
}
}
}
}
render() {
return (
<div style={this.state.profiles.length < 3 ? { width: 950, height: window.innerHeight } : { width: 950 }}>
<div style={{ flex: 1, flexDirection: "row", display: "flex" }}>
<img src={require("../images/single-02.svg")} alt="user" style={{ height: 25, width: 25, paddingLeft: 30, paddingRight: 10, paddingTop: 30, filter: "brightness(0) saturate(100%)" }} />
<h2 style={{ paddingTop: 10, color: "#000000", fontWeight: 600 }}>Users</h2>
</div>
<div style={{ flex: 1, flexDirection: "row", display: "flex" }}>
<div style={{ flex: 1 }}>
<div style={{ flex: 1, flexDirection: "row", display: "flex", justifyContent: "space-between" }}>
<p style={{ fontSize: 16, fontWeight: 600, paddingLeft: 50, paddingTop: 10 }}>New</p>
<Dropdown
options={options}
onChange={this.searchByMonth}
value={this.defaultOption}
placeholder={this.defaultOption} />
</div>
<FlatList
list={this.state.profiles}
renderItem={this.renderUserProfile}
renderWhenEmpty={() => <div style={{ flex: 1, textAlign: "center" }}>List is empty!</div>}
hasMoreItems={this.state.hasMoreItems}
loadMoreItems={this.getUsersProfilesList}
/>
</div>
<div style={{ flex: 1 }}>
<div style={{ flex: 1, flexDirection: "row", display: "flex", justifyContent: "space-between" }}>
<p style={{ fontSize: 16, fontWeight: 600, paddingLeft: 50, paddingTop: 10 }}>Flagged</p>
<Dropdown
options={options}
onChange={this.searchByMonth}
value={this.defaultOption}
placeholder="Select Date" />
</div>
<FlatList
list={this.state.usersFlagged}
renderItem={this.renderUserFlaggedPost}
renderWhenEmpty={() => <div style={{ flex: 1, textAlign: "center" }}>There are no results for this date. Try again.</div>}
/>
</div>
</div>
</div>
);
}
}
export default User;
**Desktop (please complete the following information):**
- OS: Windows/Mac
- Browser: Chrome
- Version: 84.0.4147.105 (Official Build) (64-bit)
- React and React Dom 16.8.0