Search code examples
javascriptreact-reduxredux-thunkredux-promise

using redux-thunk creates undefined error while Promise work just fine


here is my reducer:

export default function(state=[], action){
    switch (action.type) {
        case FETCH_PLACES: 
            return [action.payload.data]; 
    }
    return state;
}

and here is my flight container:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import moment from 'moment';

class FlightList extends Component {

    renderFlights(flightData){
        const result = flightData.data.length;     
        console.log(flightData);  
        var rows = [];
        for (var i = 0; i < result; i++) {
            rows.push(
            <tr key={i} >
                <td>{i+1}</td>,
                <td>{flightData.data[i].airlines[0]}</td>,
                <td>{flightData.data[i].route[0].flight_no}</td>,
                <td>{flightData.data[i].mapIdfrom}</td>,
                <td>{flightData.data[i].mapIdto}</td>,
                <td>
                    {
                        moment.unix(flightData.data[i].dTime).format("YYYY-MM-DD HH:mm")
                    }
                </td>,
                <td>
                    {
                        moment.unix(flightData.data[i].aTime).format("YYYY-MM-DD HH:mm")
                    }
                </td>,
                <td>{flightData.data[i].conversion.EUR} Euro</td>
            </tr>
            );
        }
        return <tbody>{rows}</tbody>;
    }   

    render(){
        return (
            <table className="table table-hover">
                <thead>
                    <tr>
                        <th>#</th>
                        <th>Airline</th>
                        <th>Flight Number</th>
                        <th>From</th>
                        <th>To</th>
                        <th>Departure</th>
                        <th>Arrival</th>
                        <th>Cost</th>
                    </tr>
                </thead>
                    {this.props.flights.map(this.renderFlights)}
            </table>
        );
    }
}

const mapStateToProps=({ flights })=>{
    return { flights };
};

export default connect(mapStateToProps)(FlightList);

after I used redux-thunk when I try to run my application i get the following error:

Uncaught TypeError: Cannot read property 'data' of undefined

I tried to figure out what is causing this, if at my reducer i changed [action.payload.data] to [action.payload] then I get the error:

Uncaught TypeError: Cannot read property 'length' of undefined

here is my src/index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';

//import ReduxPromise from 'redux-promise';
import thunk from 'redux-thunk';


import App from './components/app';
import reducers from './reducers';

//const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
const store = createStore(reducers,applyMiddleware(thunk));

ReactDOM.render( 
  <Provider store={store}> 
  <App /> 
  </Provider> 
  , document.querySelector('.container'));

but no matter what I always get a JSON file that contains all the information I need and in my container I try to publish them in a table formt. I dont get what is causing this. is there any way to fix this without changing my source file to what it wa before?

UPDATE

import axios from 'axios';
import moment from 'moment';

const ROOT_URL = `https://api.skypicker.com/flights`;

//to keep out action type consistent between our action creator and our action reducers
export const FETCH_PLACES = 'FETCH_PLACES';

export function createQueryString(obj){
    const Qstring = require('querystring'); 
    const newQuery = Qstring.stringify(obj);
    return newQuery;
}

export function fetchPlaces(query) {

    let skypicker = {
        flyFrom: query.from,
        //to: query.to,
        dateFrom: query.startDate,
        dateTo: query.finishDate,
        price_to: query.budget,
        partner: "picky"
        //partner_market: "yout id"
    };

    const FormattedDateFrom = moment(skypicker.dateFrom).format('DD/MM/YYYY');
    const FormattedDateTo = moment(skypicker.dateTo).format('DD/MM/YYYY');
    skypicker.dateFrom = FormattedDateFrom;
    skypicker.dateTo = FormattedDateTo;

    const queryString = createQueryString(skypicker);
    const url = `${ROOT_URL}?${queryString}`;
    const request = axios.get(url);

    return {
        type: FETCH_PLACES, 
        payload: request
    };

}

Solution

  • You did not include your action creator. The problem is in the way you work with redux-thunk.

    1. You dispatch action in your component/container
    2. If the dispatched action returns function then redux-thunk will execute that function
    3. Inside that function, you have to dispatch another action that will return an object (type and the data you got from API)

    Edit:

    This code snippet should do the work. If everything is good you should just replace your fetchPlaces action creator with my fetchPlaces action creator.

    export function fetchPlaces(query) {
      // This is your thunk because we are not retuning object but a function redux-thunk will execute this function
      return function(dispatch) {
        const skypicker = {
          flyFrom: query.from,
          dateFrom: query.startDate,
          dateTo: query.finishDate,
          price_to: query.budget,
          partner: 'picky',
        }
    
        const FormattedDateFrom = moment(skypicker.dateFrom).format('DD/MM/YYYY')
        const FormattedDateTo = moment(skypicker.dateTo).format('DD/MM/YYYY')
        skypicker.dateFrom = FormattedDateFrom
        skypicker.dateTo = FormattedDateTo
    
        const queryString = createQueryString(skypicker)
        const url = `${ROOT_URL}?${queryString}`
        axios.get(url).then(function(response) {
          // If request was successful you want to dispatch new action
          dispatch({
            type: FETCH_PLACES,
            payload: response,
          })
        })
      }
    }