Below is my container code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchMovies } from './actions';
export class Container extends Component {
componentDidMount() {
this.props.fetchMovies();
}
}
const mapStateToProps = state => {
return {
movies: state.movies,
};
};
function mapDispatchToProps(dispatch) {
return {
fetchMovies: bindActionCreators({fetchMovies}, dispatch),
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Container);
Action:
export const fetchMovies = () => dispatch => {
console.log('fetchMovies called');
// const movieResponse = fetchAPI(apiUrl);
// console.log('movieResponse => ', JSON.stringify(movieResponse));
dispatch({ type: actionTypes.FETCH_MOVIES, payload: [] });
};
Store:
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import rootReducer from '../rootReducer';
const middlewares = [thunk];
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(...middlewares))
);
export default store;
Dependency Versions:
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-bootstrap": "^1.0.0-beta.11",
"react-dom": "^16.8.6",
"react-flexbox-grid": "^2.1.2",
"react-redux": "^7.1.0",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-scripts": "3.0.1",
"redux": "^4.0.4",
"redux-actions": "^2.6.5",
"redux-promise-middleware": "^6.1.1",
"redux-thunk": "^2.3.0",
Getting error:
TypeError: this.props.fetchMovies is not a function
I am using latest react version of 16.8. Is that the reason? or am i missing something in configuration?
🎈 It is much more simple.
I don't know why you are using "thunk", I would suggest "saga" instead. I don't like the idea of adding some logic (fetching) to the actions, but any way here is your solution.
Container:
import React, { Component } from "react";
import connect from "./connect";
export class MovieList extends Component {
componentDidMount() {
this.props.fetchMovies();
}
render() {
const { isFetching, movies } = this.props;
const toLi = (movie, key) => <li key={key}>{movie.title}</li>;
return isFetching
? <span>Data is loading</span>
: <ul>{movies.map(toLi)}</ul>
}
}
export default connect(MovieList); // pay attention to this
Binding container with store, this way will keep your container much like component:
import { connect } from "react-redux";
import { fetchMovies } from "../actions";
const props = state => ({
movies: state.movies,
isFetching: state.isFetching
});
const actions = {
fetchMovies
};
export default connect(
props,
actions
);
Actions file:
export const FETCH_MOVIES = `MOVIE/FETCH_MOVIES`;
export const FETCHED_MOVIES = `MOVIE/FETCHED_MOVIES`;
export const FETCH_ERROR = `MOVIE/FETCH_ERROR`;
export const receivedMovies = movies => ({
type: FETCHED_MOVIES,
movies
});
export const onError = error => ({
type: FETCH_ERROR,
error
});
export const fetchMovies = () => dispatch => {
dispatch({type: FETCH_MOVIES})
return fetch(API_URL)
.then(res => res.json())
.then(data => dispatch(receivedMovies(data)))
.catch(err => dispatch(onError(err)));
}
🧐 A full working demo is here: https://codesandbox.io/s/7h56r
You are using bindActionCreators wrong. It takes an object as the first argument. The properties of the object are the action creators themselves.
And returns an object just like mapDispatchToProps does.
This might work
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchMovies }, dispatch)
}
Or you might not use bindActionCreators at all
function mapDispatchToProps(dispatch) {
fetchMovies: () => fetchMovies(dispatch)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With