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