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)
}
There is a slight mismatch when using the bindActionCreators function. Try like this
const matchDispatchToProps = dispatch => bindActionCreators({
fetchMovies
}, dispatch)
I don't use mapDispatchToProps i do it directly and it works perfectly
export default connect(
mapStateToProps,
{ fetchMovies }
)(Container);
You can do it two ways
const mapDispatchToProps = (dispatch) => ({
fetchMovies: () => dispatch(fetchMovies())
})
or
const mapDispatchToProps = (dispatch) => ({
fetchMovies: bindActionCreators(fetchMovies, dispatch)
})
Also, make sure you're importing the connected Container
import Container from './container'
instead of
import { Container } from './container'
From further look into your code, your actions is not a pure function, hence it led to another error. Here's a quick sample fix for your code
You need to call it like this:
this.props.actions.fetchMovies()
You may also need to update your mapDispatchToProps method. We call ours like such:
const actions = {
fetchMovies: fetchMoviesActionFunction, // or whatever your function is called here
};
const mapDispatchToProps = dispatch => ({ actions: bindActionCreators(actions, dispatch) });
I'd go another way. It's been a while since I worked with thunk last time, but I did not use mapDispatchToProps
alike methods. See if this approach does the trick for you
export class Container extends Component {
componentDidMount() {
this.props.dispatch(fetchMovies());
}
}
const mapStateToProps = state => {
return {
movies: state.movies,
};
};
export default connect(
mapStateToProps
)(Container);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.