1

I have a react-native project implemented with redux where I am trying to fetch data from an api using fetch.I am unable to fetch the data from the api.Also,it doesn't give any errors. My code is as shown below:

Action.js

//import axios from 'axios';
export const FETCH_DATA = 'fetch_data';
export const FETCH_SUCCESS = 'fetch_success';

export function fetchData() {

  return dispatch => {
    return(fetch('https://api.myjson.com/bins/fz62x'))
          .then(res => res.json())
          .then(data => {
          dispatch({
            type: FETCH_DATA,
            payload: data
          })
          }
        )
    }
}

I have 2 reducer files:

fetch_data.js

import FETCH_DATA from '../actions'

const initialState = {
  result:[],
  isFetching: false,
  error: false
}

export default function fetchReducer(state = initialState, action) {

    switch (action.type) {
      case FETCH_DATA: {
        return {
          ...state,
          isFetching: true,
          result: action.payload.data
        }
      }

      default:
        return state
    }

}

index.js

import { combineReducers } from 'redux';
import  fetchData  from './fetch_data';

const rootReducer = combineReducers({
  result: fetchData
})

export default rootReducer;

My component where I am trying to access the data fetched from the api:

HomeScreen.js

import React from 'react';
import { StyleSheet,
         Text,
         View,
         ActivityIndicator
         } from 'react-native';
import { bindActionCreators } from 'redux';
import reducer from '../reducers/fetch_data';
import thunk from 'redux-thunk';
import { connect } from 'react-redux';
import { fetchData } from '../actions';

class HomeScreen extends React.Component {
  static navigationOptions = {
    header: null
  }

  componentDidMount() {
    this.props.fetchData()
  }

    render() {
    const { result, isFetching } = this.props.result;

    if (isFetching) {
        return(
          <View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
                    <ActivityIndicator size={'large'} />
                </View>
        )
    } else {
      return(
        <View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
                   <Text>{result.length}</Text>
               </View>
      )
    }
  }
}


function mapStateToProps(state) {
  return {
    result: state.result
  }
}

function mapDispatchToProps(dispatch) {
  return {
    ...bindActionCreators({ fetchData }, dispatch)
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'blue'
  },
  welcome: {
    color: '#FFF',
    fontSize: 30
  }
})

So,in my Homescreen.js where I try to ge the result of the api in <Text>{result}</Text> ,I get a blank page. If I try to get the length of the result props,I get 0.What is the issue with this code,can anyone please help me with this?

NOTE: Also, isFetching props is returning the default value,i.e. false, so I am directly navigated to the other page where result prop is mentioned.

EDIT 1 Updated files for the action,reducer and component are given below:

Actions.js

//import axios from 'axios';
//import { FETCH_DATA, FETCH_DATA_SUCCESS, FETCH_DATA_FAILURE } from '/constants';
export const FETCH_DATA = 'FETCH_DATA';
export const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
export const FETCH_DATA_FAILURE = 'FETCH_DATA_FAILURE';


export function fetchData() {
  return (dispatch) => {
    dispatch(getData())
    fetch('https://api.myjson.com/bins/fz62x')
    .then(res => res.json())
    .then(json => dispatch(getDataSuccess(json.results)))
    .catch(err => dispatch(getDataFailure(err)))
  }
}

function getData() {
  return {
    type: FETCH_DATA
  }
}

function getDataSuccess(data) {
  return {
    type: FETCH_DATA_SUCCESS,
    data
  }
}

function getDataFailure() {
  return {
    type: FETCH_DATA_FAILURE,

  }
}

fetch_data.js

import FETCH_DATA from '../actions';
import FETCH_DATA_SUCCESS from '../actions';
import FETCH_DATA_FAILURE from '../actions';

const initialState = {
  result_array:[],
  isFetching: false,
  error: false
}

export default function fetchReducer(state = initialState, action) {

    switch (action.type) {
      case FETCH_DATA: {
        return {
          ...state,
          isFetching: true,

        }
      }

      case FETCH_DATA_SUCCESS: {
        return {
          ...state,
          isFetching: false,
          result_array: action.payload
        }
      }

      case FETCH_DATA_FAILURE:
      return {
        ...state,
        isFetching: false,
        error:true
      }

      default:
        return state
    }

}

HomeScreen.js

import React from 'react';
import { StyleSheet,
         Text,
         View,
         ActivityIndicator
         } from 'react-native';
import { bindActionCreators } from 'redux';
import reducer from '../reducers/fetch_data';
import thunk from 'redux-thunk';
import { connect } from 'react-redux';
import { fetchData } from '../actions';

class HomeScreen extends React.Component {
  static navigationOptions = {
    header: null
  }

  componentDidMount() {
    this.props.fetchData()
  }

    render() {
    const { result, isFetching } = this.props.result;

    if (isFetching) {
        return(
          <View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
                    <ActivityIndicator size={'large'} />
                </View>
        )
    } else {
      return(
        <View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
                   <Text>{result}</Text>
               </View>
      )
    }
  }
}


function mapStateToProps(state) {
  return {
    result_array: state.result.result_array
  }
}

function mapDispatchToProps(dispatch) {
  return {
    ...bindActionCreators({ fetchData }, dispatch)
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'blue'
  },
  welcome: {
    color: '#FFF',
    fontSize: 30
  }
})
2
  • return (fetch('url')).then looks a bit weird. Maybe try return fetch(url).then? Commented Jan 10, 2018 at 3:44
  • @bozdoz ,its not working.i tried doing it the way you suggested.Am I writing the function incorrectly or what else may be the issue? Commented Jan 10, 2018 at 4:10

3 Answers 3

1

There are a few things you need to fix. It would be better if you upload the codes to github or codesandbox then we can understand you code structure easier.

First of all, return (fetch('url')).then or return fetch(url).then, both of them work as you expect, but you should keep in mind that the redux-thunk doesn't care about you return value, this promise has nothing to do, that's alright, it doesn't need to do anything.

Let's fix your syntax error in fetch_data.js first:

import FETCH_DATA from '../actions'

should be :

import { FETCH_DATA } from '../actions' // I don't know why didn't your build tool report an error here.

According to your purpose, I think you should import the FETCH_SUCCESS here as well.

Then we can talk about your action and reducer flow :

return(fetch('https://api.myjson.com/bins/fz62x'))
   .then(res => res.json())
      .then(data => {
      dispatch({
        type: FETCH_DATA,
        payload: data
      })
      }
    )
}

and reducer :

switch (action.type) {
  case FETCH_DATA: {
    return {
      ...state,
      isFetching: true,
      result: action.payload.data
    }
  }

  default:
    return state
}

You only deal with FETCH_DATA(and I think you probably should use FETCH_SUCCESS here), another action type should be dispatch and parse as well.

I will suggest the flow like this :

Action.js:

export const FETCH_DATA = "fetch_data";
export const FETCH_SUCCESS = "fetch_success";

export function fetchData() {
return dispatch => {
    fetch("https://api.myjson.com/bins/fz62x")
      .then(res => res.json())
      .then(data => {
        dispatch({
          type: FETCH_SUCCESS,
          payload: data
        });
      });

    dispatch({
      type: FETCH_DATA
    });
  };
}

With this you now dispatch FETCH_DATA to tell the application you start to fetch data first, and dispatch FETCH_SUCCESS when fetch succeed.

And the fetch_data.js:

import { FETCH_DATA, FETCH_SUCCESS } from "./actions";

const initialState = {
  result: [],
  isFetching: false,
  error: false
};

export default function fetchReducer(state = initialState, action) {
  switch (action.type) {
    case FETCH_DATA: {
      return {
        ...state,
        isFetching: true,
        error: false
      };
    }

    case FETCH_SUCCESS: {
      return {
        result: action.payload, // The action.payload.data isn't what you want
        isFetching: false,
        error: false
      };
    }

    default:
      return state;
  }
}

And now your reducer will respond correctly with FETCH_DATA and FETCH_SUCCESS

And another thing is I don't know why you import thunk and reducer in your Homescreen.js, it should not be there if you are not going to create you redux store there (I assume that you have a <Provider store={store}>{...your application}</Provider> upon the Homescreen which you should have)

Sign up to request clarification or add additional context in comments.

5 Comments

Hi, I have uploaded the project to github.Here is the link: github.com/PranamiBG/Test/tree/master/Test_app .Can you please have a look at it?
@pranami I sent you an pull request.
Checking,just give me few mins.will update you asap.
Thank you so much.This is working perfectly.It gives the count now.One more doubt I have.If I want to get the individual values from the api and put it in a TabNavigator,for eg. if I want the status property from the api and want to fill the tabs in my tabNavigator after the individual status are retrieved,and show the details for each status in their specific tabs,then how will I need to proceed.Can you just brief me about that.If you want, I will ask a separate question for that.Can you please tell me how to proceed in such scenario.And Thanks once again for helping me solve my issue .
@pranami Let's do this in your github issue.
1

I'm not sure about your problem but hope this help.

First, Your Action.js, you dispatch payload with array:

dispatch({
  type: FETCH_DATA,
  payload: data
})

that data is array

[
  { createdOn: '', taskList: [{}, {}, ...] },
  { createdOn: '', taskList: [{}, {}, ...] },
  ...
]

In your fetch_data.js You received payload with array but access .data it will got undefined, you have to change to result: action.payload

return {
  ...state,
  isFetching: true,
  result: action.payload.data // <-- undefined
}

but I think you should have type FETCH_DATA to return { isFetching: true } and FETCH_SUCCESS return { isFetching: false, result: action.payload like this

// action.js

fetchData() {
  dispatch({
    type: FETCH_DATA
  })

  return fetch('https://api.myjson.com/bins/fz62x')
    .then(res => res.json())
    .then(data => {
      dispatch({
        type: FETCH_SUCCESS,
        payload: data
      })
    })
}

// fetch_data.js

switch (action.type) {
  case FETCH_DATA: {
    return {
      ...state,
      isFetching: true
    }
  }
  case FETCH_SUCCESS: {
    return {
      ...state,
      isFetching: false,
      result: action.payload
    }
  }
}

but It looks a bit weird because you got 0 when use get the length of result, it should be undefined unless it return defaultValue of state that result is empty array

4 Comments

Hi, I tried changing my action and reducer files , but it's giving an error in props.Just give a min,I will upload the updated files in an edit above.
I have pasted all the updated files above in an edit.Can you please have a look once.
@pranami Your updated files are dispatch FETCH_DATA_SUCCESS with data as a key but your fetch_data.js is received payload key
I'm not sure about json.results in fetch() function is it array?
1

You must have 50 reputation to comment

Sorry, but i just seen that your edit 1 has something wrong. iam i right

case FETCH_DATA_SUCCESS: {
    return {
      ...state,
      isFetching: false,
      result_array: action.payload <-- this is undefined. it should be action.data from your action
    }
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.