2

I'm absolutely new in React Native.
So I start learn to create a simple application.
I want to use Zomato API for my application.
Everything works fine until I try to use an API which causing this error :
I really need help for this, so I can continue to learn.
Any help would be really appreciated. Thank you.


enter image description here

Here are my Homescreen and Api files :
MainViewScreen.js

import React, { Component } from 'react'
import { Picker, TouchableOpacity, View, ListView, Text } from 'react-native'
import { connect } from 'react-redux'
import { Icon, Header } from 'react-native-elements'
import { Button, Container, Content, Footer, Title} from 'native-base'
import API from '../Services/Api'

// For empty lists
// import AlertMessage from '../Components/AlertMessage'

// Styles
import styles from './Styles/MainRestoStyles'

class MainRestoScreen extends React.Component {
  constructor (props) {
    super(props)

    /* ***********************************************************
    * STEP 1
    * This is an array of objects with the properties you desire
    * Usually this should come from Redux mapStateToProps
    *************************************************************/
    const dataObjects = []
    /* ***********************************************************
    * STEP 2
    * Teach datasource how to detect if rows are different
    * Make this function fast!  Perhaps something like:
    *   (r1, r2) => r1.id !== r2.id}
    *   The same goes for sectionHeaderHasChanged
    *************************************************************/
    const rowHasChanged = (r1, r2) => r1 !== r2
    const sectionHeaderHasChanged = (s1, s2) => s1 !== s2

    // DataSource configured
    this.ds = new ListView.DataSource({rowHasChanged, sectionHeaderHasChanged})

    // Datasource is always in state
    this.state = {
      dataSource: this.ds.cloneWithRowsAndSections(dataObjects)
    }

    this.stateCity = { city: "ny" }

    this.getRestoCategories
  }

  /* ***********************************************************
  * STEP 3
  * `renderRow` function -How each cell/row should be rendered
  * It's our best practice to place a single component here:
  *
  * e.g.
    return <MyCustomCell title={rowData.title} description={rowData.description} />
  *************************************************************/
  renderRow (rowData, sectionID) {
    // You can condition on sectionID (key as string), for different cells
    // in different sections
    return (
      <TouchableOpacity style={styles.row}>
        <Text style={styles.boldLabel}>Section {sectionID} - {rowData.title}</Text>
        <Text style={styles.label}>{rowData.description}</Text>
      </TouchableOpacity>
    )
  }

  /* ***********************************************************
  * STEP 4
  * If your datasource is driven by Redux, you'll need to
  * reset it when new data arrives.
  * DO NOT! place `cloneWithRowsAndSections` inside of render, since render
  * is called very often, and should remain fast!  Just replace
  * state's datasource on newProps.
  *
  * e.g.
    componentWillReceiveProps (newProps) {
      if (newProps.someData) {
        this.setState(prevState => ({
          dataSource: prevState.dataSource.cloneWithRowsAndSections(newProps.someData)
        }))
      }
    }
  *************************************************************/

  // Used for friendly AlertMessage
  // returns true if the dataSource is empty
  noRowData () {
    return this.state.dataSource.getRowCount() === 0
  }

  render () {
    return (
      <Container>
        <View style={styles.toolbar}>
          <Text style={styles.toolbarButton}></Text>
          <Icon name='bowl' type='entypo' size={40} color='white'/> 
          <Picker
            style={styles.dropdown}
            selectedValue={this.state.city}
            onValueChange={(city) => this.setState({city})}>
            <Picker.Item label="New York City" value="ny" />
            <Picker.Item label="New Jersey" value="nj" />
            <Picker.Item label="Los Angeles" value="la" />
            <Picker.Item label="Oklahoma City" value="oc" />
          </Picker> 
        </View>
        <View  style={styles.viewDropdown}>
          
        </View>
        <Content>        
          <ListView
            contentContainerStyle={styles.listContent}
            dataSource={this.state.dataSource}
            onLayout={this.onLayout}
            renderRow={this.renderRow}
            enableEmptySections
          />
        </Content>
        <Footer style={ styles.bars }>
          <Button transparent style={ styles.buttonsMenu }>
            <Icon name='location' type='entypo' color='white' size={30}/>
          </Button>
          <Button transparent style={ styles.buttonsMenu }>
            <Icon name='heart' type='foundation' color='white' size={30}/>
          </Button>
          <Button transparent style={ styles.buttonsMenu }>
            <Icon name='bell' type='entypo' color='white' size={30}/>
          </Button>
        </Footer>
      </Container>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    // ...redux state to props here
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
  }
}

getRestoCategories = async () => {
  const api = API.create()
  const categories = await api.getCategories()
  this.setState({
  datasource: this.ds.cloneWithRowsAndSections[categories.data]
  })
}

export default connect(mapStateToProps, mapDispatchToProps)(MainRestoScreen)

Api.js

// a library to wrap and simplify api calls
import apisauce from 'apisauce'

// our "constructor"
const create = (baseURL = 'https://developers.zomato.com/api/v2.1/') => {
  // ------
  // STEP 1
  // ------
  //
  // Create and configure an apisauce-based api object.
  //
  const api = apisauce.create({
    // base URL is read from the "constructor"
    baseURL,
    // here are some default headers
    headers: {
      'Cache-Control': 'no-cache'
    },
    // 10 second timeout...
    timeout: 10000
  })

  // ------
  // STEP 2
  // ------
  //
  // Define some functions that call the api.  The goal is to provide
  // a thin wrapper of the api layer providing nicer feeling functions
  // rather than "get", "post" and friends.
  //
  // I generally don't like wrapping the output at this level because
  // sometimes specific actions need to be take on `403` or `401`, etc.
  //
  // Since we can't hide from that, we embrace it by getting out of the
  // way at this level.
  //
  const getCategories = () => api.get('categories') 

  // ------
  // STEP 3
  // ------
  //
  // Return back a collection of functions that we would consider our
  // interface.  Most of the time it'll be just the list of all the
  // methods in step 2.
  //
  // Notice we're not returning back the `api` created in step 1?  That's
  // because it is scoped privately.  This is one way to create truly
  // private scoped goodies in JavaScript.
  //
  return {
    // a list of the API functions from step 2
    getCategories
  }
}

// let's return back our create method as the default.
export default {
  create
}
kurniawan26
  • 793
  • 4
  • 16
  • 35

1 Answers1

0

so first of all, you should understand the component lifecycle of React: enter image description here

You are trying to call the api in the constructor. Best practice would be to call the api on ComponentDidMount() Method. Currently your calling your api in the constructor, when the initialState isn’t set.

What i also see is that the error is thrown from redux-saga. Did you integrate redux-saga in your project? If so, you should let redux-saga handle your side effects, like async calls.

Could you provide your full code of the Project?

Where do you configure your store?

And did you probably add redux-saga as middleware to redux?

Greetings

  • Hi.. thanks for the response..You may want to check my repo https://github.com/JayKurniawan/ReactResto – kurniawan26 Dec 08 '17 at 15:51
  • I'm basically don't know anything about how to configure redux-saga.. I've looking for guide, found some..but those example still to hard for me to understand..you may want to tell where is the best place to understand ho to implement API – kurniawan26 Dec 08 '17 at 15:56
  • 1
    First of all, you should Unterstand How reacht Works. Do. the Basic Training so that you get the React way of thinking. Then you should take a Look at redux, and How reduxs works, redux-Saga can Be used without redux, but it is basically a redux middleware. Start with this: https://reactjs.org/docs/thinking-in-react.html, Then redux https://redux.js.org, take a Look at Basic example then async, dan is using thunk as middleware. When you Understand How redux an react work you can take a Look at redux-Saga, bur honestly, is your api is not that complicated i would rather User redux thunk –  Dec 08 '17 at 16:12
  • You may only want to dispatch async actions, and the generator Syntax of redux-Saga can Be confusing. And please read the section with "you may not Need redux" simple api calls can Be done with isomproic fetch and react, no ned for redux. –  Dec 08 '17 at 16:13