Reputation: 117
I am using react-native FlatList component to render a list. Im fetching dummy data from an action but my pagination is not acting as expected, it's rendering everything instantly when I'm using onEndReached.
what am i missing?
check my expo https://snack.expo.io/@thesvarta/19d294
so here are my actions
import { FETCH_FEED, MORE_FEED, REFRESH_FEED } from './actionTypes';
export const fetchFeed = () => {
return async (dispatch, getState) => {
const url = 'https://reqres.in/api/users?page=' + 1;
const response = await fetch(url, {
method: 'GET',
});
if (!response.ok) {
const errorResData = await response.json();
let message = 'error';
throw new Error(message);
}
const resData = await response.json();
dispatch({
type: FETCH_FEED,
data: resData.data,
page: 1,
rows: 1,
message: resData.MESSAGE,
});
};
};
export const fetchRefreshFeed = () => {
return async (dispatch, getState) => {
const url = 'https://reqres.in/api/users?page=' + 1;
const response = await fetch(url, {
method: 'GET',
});
if (!response.ok) {
const errorResData = await response.json();
let message = 'error';
throw new Error(message);
}
const resData = await response.json();
dispatch({
type: REFRESH_FEED,
refresh_data: resData.data,
refresh_page: 1,
refresh_rows: 1,
refresh_message: resData.MESSAGE,
});
};
};
export const loadMoreFeed = page => {
return async (dispatch, getState) => {
const url = 'https://reqres.in/api/users?page=' + page;
const response = await fetch(url, {
method: 'GET',
});
if (!response.ok) {
const errorResData = await response.json();
let message = 'error';
throw new Error(message);
}
const resData = await response.json();
dispatch({
type: MORE_FEED,
more_data: resData.data,
more_page: page,
more_rows: 1,
more_message: resData.MESSAGE,
});
};
};
My reducers
import { FETCH_FEED, REFRESH_FEED, MORE_FEED } from '../actions/actionTypes';
const initialState = {
data: [],
error: null,
page: 1,
rows: 1,
message: null,
};
export default (state = initialState, action) => {
switch (action.type) {
case FETCH_FEED:
return {
data: action.data,
page: action.page,
rows: action.rows,
message: action.message,
};
case REFRESH_FEED:
return {
data: action.refresh_data,
page: action.refresh_page,
rows: action.refresh_rows,
};
case MORE_FEED:
return {
data: [...state.data, ...action.more_data],
page: action.more_page,
rows: action.more_rows,
};
default:
return state;
}
};
My component
import React, {
useState,
useEffect,
useReducer,
useCallback,
getState,
} from 'react';
import { Navigation } from 'react-navigation';
import {
StyleSheet,
View,
Text,
StatusBar,
TouchableHighlight,
TouchableOpacity,
FlatList,
Image,
Modal,
Linking,
ScrollView,
Alert,
} from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import * as feedActions from '../../store/actions/feed';
const FeedScreen = props => {
const [error, setError] = useState();
const [refresh, setRefresh] = useState(false);
const dispatch = useDispatch();
const state = useSelector(state => state.feed);
const loadFeed = useCallback(async () => {
setError(null);
try {
await dispatch(feedActions.fetchFeed(state.page, state.rows));
} catch (err) {
setError(err.message);
}
}, [dispatch, setError]);
useEffect(() => {
loadFeed();
}, [loadFeed]);
const refreshFeed = useCallback(async () => {
setError(null);
setRefresh(true);
try {
await dispatch(feedActions.fetchRefreshFeed());
} catch (err) {
setError(err.message);
}
setRefresh(false);
}, [dispatch, setError, setRefresh]);
const morefeed = useCallback(async () => {
setError(null);
try {
await dispatch(feedActions.loadMoreFeed(state.page + 1));
} catch (err) {
setError(err.message);
}
}, [dispatch, setError]);
const renderRow = ({ item, index }) => {
return (
<View key={index}>
<Text>{item.email}</Text>
</View>
);
};
if (error != null) {
return (
<View style={styles.centered}>
<Text>An error occurred!</Text>
<TouchableOpacity onPress={() => refreshFeed()}>
Try again
</TouchableOpacity>
</View>
);
}
return (
<View style={styles.MainContainer}>
<FlatList
data={state.data}
renderItem={renderRow}
onRefresh={refreshFeed}
refreshing={refresh}
keyExtractor={(item, index) => index.toString()}
onEndReached={morefeed}
onEndReachedThreshold={0.5}
/>
</View>
);
};
const styles = StyleSheet.create({
MainContainer: {
flex: 1,
backgroundColor: 'rgb(243,243,248)',
},
});
export default FeedScreen;
Upvotes: 1
Views: 1907
Reputation: 2413
You basically need a way to stop dispatching the loadMoreFeed
action. This is the reason almost all server-sided paginations include either the next page number or the total number of pages.
I have added a simple page number check on your action:
if(page <= totalPages) {
const url = 'https://reqres.in/api/users?page=' + page;
const response = await fetch(url, {
method: 'GET',
});
if (!response.ok) {
const errorResData = await response.json();
let message = 'error';
throw new Error(message);
}
const resData = await response.json();
dispatch({
type: MORE_FEED,
more_data: resData.data,
more_page: page,
more_rows: 1,
totalPages: resData.total_pages,
more_message: resData.MESSAGE,
});
}
I have edited your snack with the fix, and you can find it at this link: https://snack.expo.io/rJmsZu0iS
Again, this is just a very simple method of keeping track of the number of pages. You would probably want to change it in production.
Upvotes: 1