mtwallet
mtwallet

Reputation: 5086

Redux fetch data from api

I am trying to fetch some data from an api using Redux. My code looks like this:

Action:

// Import libraries
import axios from 'axios';

// Import types
import {
  GET_ALL_PICKS
} from './types';

export const getAllPicks = ({ token }) => {
  const getPicks = (dispatch) => {
    axios({
      method: 'get',
      url: 'http://myapi/',
      headers: {
        Authorization: `Bearer ${token}`
      }
    })
    .then((response) => {
      console.log(response.data); // First log here returns data just fine
      dispatch({
        type: GET_ALL_PICKS,
        payload: response.data
      });
    })
    .catch((error) => {
      console.log(error);
    });
  };

  return getPicks;
};

Reducer:

// Import types
import {
  GET_ALL_PICKS
} from '../actions/types';

// Set Initial State
const INITIAL_STATE = {
  allPicks: {},
  loading: false,
  error: ''
};

// Make pick reducers
export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case GET_ALL_PICKS:
      return { ...state, allPicks: action.payload }; // Logging action.payload here returns data just fine
    default:
      return state;
  }
};

Component:

// Import Libraries
import React, { Component } from 'react';
import { Text } from 'react-native';
import { connect } from 'react-redux';
import {
  getAllPicks
} from '../actions/picks';

// Make Component
class HomeScreen extends Component {
  // Fetch Data
  componentWillMount() {
    const { token } = this.props;

    this.props.getAllPicks({ token });
  }

  // Test response
  componentDidMount() {
    console.log(this.props.allPicks); // This log returns empty object, why?!
  }

  render() {
    return (
      <Text>Test</Text>
    );
  }
}

const mapStateToProps = ({ auth, picks }) => {
  const { token } = auth;
  const { allPicks } = picks;

  return {
    token,
    allPicks
  };
};

export default connect(mapStateToProps, { getAllPicks })(HomeScreen);

When I run the app I see the data in the action console.log and if I run a console.log(action.payload) in the reducer I see the data just fine but in component I see an empty array which suggests I'm not hooking up the data in my reducer correctly? Here's a screen shot of the logs:

enter image description here

I have also tried this in my reducer after some Googling:

  return Object.assign({}, state, {
    allPicks: action.payload
  });

but again I got the same result. Can anyone explain to me what I am doing wrong?

Upvotes: 0

Views: 1026

Answers (1)

Antoine Jaussoin
Antoine Jaussoin

Reputation: 5172

You are confusing the component lifecycle and the API lifecycle.

In practice, what's happening is:

  • componentWillMount
  • getAllPicks
  • componentDidMount (at which point, the API didn't return, the picks are empty)
  • [... wait for the API to return]
  • then the API returns with the data, but too late

What you need to do then is check for your "picks" state in the render() function, which will be updated each time your state changes (which happens when the API returns), thanks to the connect() function.

You can also check that the picks are updated properly using componentWillUpdate, not componentDidMount which again has nothing to do with the props being updated.

Upvotes: 3

Related Questions