Reputation: 8448
I am using react-infinite-scroll-component
package as a way to load data when users keep scrolling (infinite scrolling). However, when I set it all up with Redux and everything, and if I scroll to the bottom, I get the following error on my action method:
TypeError: dispatch is not a function
These are my files for replication or more context:
TopRatedComponent.js:
import React, { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { connect } from "react-redux";
import { fetchTopRatedMovies } from '../actions/topRatedAction.js';
import { Container, Row, Col, Button } from 'react-bootstrap';
import { useDispatch } from "react-redux";
import InfiniteScroll from "react-infinite-scroll-component";
const TopRatedComponent = (props) => {
const dispatch = useDispatch();
let [page, setPage] = useState(3);
useEffect(() => {
dispatch(fetchTopRatedMovies(page));
setPage = page++;
}, [])
const {
topRatedMovies,
loading,
error
} = useSelector(state => state.topRatedMovies);
return (
<div >
{loading && <div>LOADING...</div>}
{error && <div>{error}</div>}
<Container className="p-4" >
<InfiniteScroll
dataLength={20}
next={fetchTopRatedMovies(page)}
hasMore={true}
loader={<h4>Loading...</h4>}
>
{topRatedMovies.results && topRatedMovies.results.map(topRated => (
<div key={topRated.id}>
div - #{topRated.title}
</div>
))}
</InfiniteScroll>
</Container>
</div>
)
};
const mapStateToProps = state => {
const { topRatedMovies, loading, error } = state.topRatedMovies;
return {
topRatedMovies,
loading,
error
};
};
export default connect(
mapStateToProps,
{
fetchTopRatedMovies
}
)(TopRatedComponent);
store.js:
import { createStore, compose, applyMiddleware, combineReducers } from "redux";
import thunkMiddleware from 'redux-thunk'
import topRatedReducer from '../reducers/topRatedReducer'
const rootReducer = combineReducers({
topRatedMovies: topRatedReducer
});
const store = createStore(rootReducer, compose(applyMiddleware(thunkMiddleware),
));
export default store;
topRatedAction.js:
import {
FETCH_TOPRATED_START,
FETCH_TOPRATED_FAILURE,
FETCH_TOPRATED_SUCCESS
} from './actionTypes'
import axios from "axios";
const API_KEY = 'MyAPIKEY';
export const fetchTopRatedMovies = (page) => {
// page = 1;
const API_URL = `https://api.themoviedb.org/3/movie/top_rated?api_key=${API_KEY}&language=en-US&page=` + page;
return dispatch => {
dispatch(fetchTopRatedStarted());
axios.get(API_URL)
.then(response => {
dispatch(fetchTopRatedSucceeded(response.data));
})
.catch(error =>{
dispatch(fetchTopRatedFailed(error.message));
});
};
};
const fetchTopRatedStarted = () => {
return{
type: FETCH_TOPRATED_START,
payload: {
isLoading: true
}
};
};
const fetchTopRatedSucceeded = topRatedMovies => {
return{
type: FETCH_TOPRATED_SUCCESS,
payload: {
topRatedMovies
}
};
};
const fetchTopRatedFailed = error => {
return{
type: FETCH_TOPRATED_FAILURE,
payload: {
error
}
};
};
topRatedReducer.js
import {
FETCH_TOPRATED_START,
FETCH_TOPRATED_FAILURE,
FETCH_TOPRATED_SUCCESS
} from '../actions/actionTypes'
const initialState = {
topRatedMovies: [],
loading: false,
error: null
}
export default function (state = initialState, action){
switch (action.type) {
case FETCH_TOPRATED_START:
return{
...state,
loading: true
};
case FETCH_TOPRATED_FAILURE:
return{
...state,
loading: false,
error: action.payload.error
}
case FETCH_TOPRATED_SUCCESS:
return{
...state,
loading:false,
topRatedMovies: action.payload.topRatedMovies
};
default:
return state
}
}
Upvotes: 0
Views: 361
Reputation: 281764
Since you are using connect and passing fetchTopRatedMovies
already to mapDispatchToProps, you can simply useed the dispatch function from props rather than calling dispatch on the imported function
Also the next props of InfiniteScroll shouldn't use fetchTopRatedMovies
directly but from props since thaat will be the dispatched function instance. Your updated code will look like
const TopRatedComponent = (props) => {
let [page, setPage] = useState(3);
useEffect(() => {
props.fetchTopRatedMovies(page);
setPage(page => page+1); // call setPage function
}, [])
const {
topRatedMovies,
loading,
error
} = props
const fetchData = () => {
props.fetchTopRatedMovies(page);
setPage(page => page + 1);
}
return (
<div >
{loading && <div>LOADING...</div>}
{error && <div>{error}</div>}
<Container className="p-4" >
<InfiniteScroll
dataLength={20}
next={fetchData}
hasMore={true}
loader={<h4>Loading...</h4>}
>
{topRatedMovies.results && topRatedMovies.results.map(topRated => (
<div key={topRated.id}>
div - #{topRated.title}
</div>
))}
</InfiniteScroll>
</Container>
</div>
)
};
const mapStateToProps = state => {
const { topRatedMovies, loading, error } = state.topRatedMovies;
return {
topRatedMovies,
loading,
error
};
};
export default connect(
mapStateToProps,
{
fetchTopRatedMovies
}
)(TopRatedComponent);
or
import React, { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { connect } from "react-redux";
import { fetchTopRatedMovies } from '../actions/topRatedAction.js';
import { Container, Row, Col, Button } from 'react-bootstrap';
import { useDispatch } from "react-redux";
import InfiniteScroll from "react-infinite-scroll-component";
const TopRatedComponent = (props) => {
const dispatch = useDispatch();
let [page, setPage] = useState(3);
useEffect(() => {
dispatch(fetchTopRatedMovies(page));
setPage(page => page+1); // call setPage function
}, [])
const {
topRatedMovies,
loading,
error
} = useSelector(state => state.topRatedMovies);
const fetchData = () => {
dispatch(fetchTopRatedMovies(page));
setPage(page => page + 1);
}
return (
<div >
{loading && <div>LOADING...</div>}
{error && <div>{error}</div>}
<Container className="p-4" >
<InfiniteScroll
dataLength={20}
next={fetchData}
hasMore={true}
loader={<h4>Loading...</h4>}
>
{topRatedMovies.results && topRatedMovies.results.map(topRated => (
<div key={topRated.id}>
div - #{topRated.title}
</div>
))}
</InfiniteScroll>
</Container>
</div>
)
};
export default TopRatedComponent; // Note that we are not using connect here
P.S. Note that you don't need to use both connect and hooks like useSelector and useDispatch, you can use either one of them. Following any one of the above approaches will work for you.
Upvotes: 1
Reputation: 20
const infinite = () => {
dispatch(fetchTopRatedMovies(page));
setPage=page++;
};
then call infinite from next
next={infinite}
Upvotes: 1