0

I'm trying to fetch test API using FetchAPI and Redux.

The problem is with dispatch redux action.

Here's my code:

ProductList.js
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as productActions from '../actions/product';
import RaisedButton from 'material-ui/RaisedButton';

function fetchProductsWithRedux() {
    console.log("fetchProductsWithRedux-1");
    return (dispatch) => {
        console.log("fetchProductsWithRedux-2");
        dispatch(this.props.action.fetchProdutcsRequest());
        return fetchProdutcs().then(([response, json]) => {
            if (response.status === 200) {
                console.log("success");
                dispatch(this.props.action.fetchProductsSucesss(json))
            }
            else {
                console.log("error");
                dispatch(this.props.action.fetchProductsError())
            }
        })
    }
}

function fetchProdutcs() {
    const URL = "https://jsonplaceholder.typicode.com/posts";
    return fetch(URL, { method: 'GET' })
        .then(response => Promise.all([response, response.json()]));
}


class ProductList extends Component {
    constructor(props) {
        super(props);
        this.state = {
            productList: [
                'product 1',
                'product 2',
                'product 3'
            ]
        }
    }
    componentDidMount() {
        fetchProductsWithRedux();
    }
    render() {
        return (
            <div className="ProductList">
                <h2>Products</h2>
                <ul>
                    {
                        this.props.posts &&
                        this.props.posts.map((post) => {
                            return (
                                <li>{post.title}</li>
                            )
                        })
                    }
                </ul>

                <ol>
                    <RaisedButton label="Get Products Action" onClick={this.props.action.getProducts} />
                </ol>
            </div>
        );
    }
}

function mapStateToProps(state, props) {
    return {
        product: state.product,
        posts: state.posts
    };
}
function mapDispatchToProps(dispatch) {
    return {
        action: bindActionCreators(productActions, dispatch)
    }
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductList);

product.js (actions)

export function fetchProductsRequest() {
  console.log('fetchProductsRequest');
  return {
    type: 'FETCH_PRODUCTS_REQUEST'
  }
}

export function fetchProductsSuccess(payload) {
  console.log('fetchProductsSuccess');
  return {
    type: 'FETCH_PRODUCTS_SUCCESS'
  }
}

export function fetchProductsError() {
  console.log('fetchProductsError');
  return {
    type: 'FETCH_PRODUCTS_ERROR'
  }
}

product.js (reducer)

export default(state = [], payload) => {
    switch (payload.type) {
        case 'FETCH_PRODUCTS_REQUEST':
            console.log('FETCH_PRODUCTS_REQUEST action');
            return state;
        case 'FETCH_PRODUCTS_SUCCESS':
            console.log('FETCH_PRODUCTS_SUCCES action');
            return {...state, posts: payload.payload}
        default:
            return state;
    }
};

store.js

import { createStore } from 'redux';
import rootReducer from './reducers';

export default(initialState) => {
    return createStore(rootReducer, initialState);
}

Product.js (pages, component)
import React, { Component } from 'react';
import ProductList from '../../components/ProductList';
import RaisedButton from 'material-ui/RaisedButton';
//import './Product.css';

class Product extends Component {
    render() {
        return (
            <div className="Product">
                <h1>ProductList Page</h1>
                <RaisedButton label="Default" />
                <ProductList />
            </div>
        );
    }
}
export default Product;

The line console.log("fetchProductsWithRedux-2"); in ProductList.js has never been reached.

What's wrong? Any ideas? Thanks in advance.

mskuratowski
  • 4,014
  • 15
  • 58
  • 109

3 Answers3

2

seem you missed import thunk from 'redux-thunk'. You can't return a function in redux action if you dont use any middleware like 'redux-thunk'

M.Tae
  • 1,437
  • 1
  • 14
  • 24
1

There are a few issues with your code.

Firstly, fetchProductsWithRedux is an action, so you would need to dispatch it rather than calling it directly. As Bjoern mentioned, the way you are calling it, the function call just returns a function, which is never called.

Now, you cannot dispatch it in the current scenario, as it returns a function, rather than object. To fix that, you will have to use redux-thunk, which will allow it to dispatch a function.

You can add it to mapDispatchToProps, as you did for getProducts, but there is a shorthand for that. In your mapDispatchToProps, you can do the following:-

 const mapDispatchToProps = { fetchProductsWithRedux, getProducts }

You will notice that it is just returning an object with 2 functions.

From the documentation:

If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a dispatch call so they may be invoked directly, will be merged into the component’s props.

So, it will do exactly what you did earlier with bindActionCreators, but it looks more elegant. Now, instead of onClick={this.props.action.getProducts}, you can do onClick={this.props.getProducts}. Notice the missing action.

Also, your import will change to

import { getProducts } from '../actions/product';

Now, to fix your issue, in componentDidMount, rather than calling the function directly, you will have to do:-

componentDidMount() {
   this.props.fetchProductsWithRedux();
}

Hopefully, this will help.

Abhishek Jain
  • 2,957
  • 23
  • 35
0
function fetchProductsWithRedux() {
console.log("fetchProductsWithRedux-1");
return (dispatch) => {
    console.log("fetchProductsWithRedux-2");
    ...
    }

This returns a function function(dispatch){...}, which is not called in

componentDidMount() {
    fetchProductsWithRedux();
}
Björn Böing
  • 1,662
  • 15
  • 23