Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure mapDispatchToProps with react redux?

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?

like image 837
Mithun Shreevatsa Avatar asked Jan 22 '26 10:01

Mithun Shreevatsa


2 Answers

🎈 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

like image 111
sultan Avatar answered Jan 24 '26 01:01

sultan


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)
}
like image 39
Mukesh Soni Avatar answered Jan 23 '26 23:01

Mukesh Soni