I want to infinite scroll to fetch any items, the brief step is:
1) scroll at the end of screen.
2) use redux to update items pageIndex.
3) use componentDidUpdate
to catch this redux action.
4) append the fetch items to the end of items' array.
class InfiniteScroll extends React.Component {
componentDidMount() {
window.addEventListener("scroll", throttle(this.onScroll, 500), false);
}
componentWillUnmount() {
window.removeEventListener("scroll", this.onScroll, false);
}
componentDidUpdate(preProps) {
if (props.pageindex === preProps.pageindex + 1)
fetchItems(...);
}
onScroll = () => {
if (
window.innerHeight + window.scrollY >=
document.body.offsetHeight - 100
) {
updatePage(...);
}
};
render() {
return <Component {...this.props} />;
}
}
The only problem with this code is when updatePage
executes once, the fetchItems
can not follow it immediately.
Since you are using redux, your list of items should be controlled via actions/reducer.
InfiniteScroll.js:
onScroll () {
var nearBottom = window.innerHeight + window.scrollY >= document.body.offsetHeight - 100;
if (!this.props.fetching && nearBottom) {
fetchItems(); // dispatch action
}
}
render () {
var items = this.props.items.map(item => (<Component {item}/>)
return (
<ul>{ items }</ul>
)
}
componentDidMount() {
window.addEventListener("scroll", this.onScroll.bind(this), false);
}
componentWillUnmount() {
window.removeEventListener("scroll", this.onScroll.bind(this), false);
}
actions:
fetchItems () {
return dispatch => {
dispatch({
type: "FETCH_ITEMS"
});
fetch("/api/items")
.then(items => {
dispatch(itemsReceived(items));
});
}
}
itemsReceived (items) {
return {
type: "ITEMS_RECEIVED",
payload: {
items: items
}
}
}
reducer:
case "FETCH_ITEMS":
return {
...prevState,
fetching: true
case "ITEMS_RECEIVED":
return {
...prevState,
fetching: false,
items: prevState.items.concat(items)
}
This way, a clearly defined action (FETCH_ITEMS) is triggered by the scroll. Using redux-thunk
, the action makes an API call to fetch the new items. When that call is complete, you dispatch a new action to feed the new items through the reducer.
The reducer then updates the state, causing <InfiniteScroll>
to rerender with an updated list of items.
NOTE: you should also set fetching to false in the case of an error.