【问题标题】:React Native API implementations causing errorsReact Native API 实现导致错误
【发布时间】:2017-12-08 08:50:09
【问题描述】:

我是 React Native 的新手。
所以我开始学习创建一个简单的应用程序。
我想为我的应用程序使用 Zomato API。
在我尝试使用导致此错误的 API 之前,一切正常:
我真的需要帮助,所以我可以继续学习。
任何帮助将不胜感激。谢谢。


这是我的主屏幕和 Api 文件:
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
}

【问题讨论】:

    标签: android react-native redux saga


    【解决方案1】:

    所以首先,你应该了解 React 的组件生命周期:

    您正在尝试在构造函数中调用 api。最佳做法是在 ComponentDidMount() 方法上调用 api。 当前,当 initialState 未设置时,您在构造函数中调用您的 api。

    我还看到错误是从 redux-saga 抛出的。你在你的项目中集成了 redux-saga 吗?如果是这样,你应该让 redux-saga 处理你的副作用,比如异步调用。

    您能否提供该项目的完整代码?

    您在哪里配置商店?

    您是否可能将 redux-saga 作为中间件添加到 redux 中?

    问候

    【讨论】:

    • 嗨..感谢您的回复..您可能想查看我的回购github.com/JayKurniawan/ReactResto
    • 我对如何配置 redux-saga 基本上一无所知.. 我正在寻找指南,找到了一些.. 但这些示例仍然让我难以理解..you可能想知道哪里是理解 ho 实现 API 的最佳位置
    • 首先,您应该了解reacht 的工作原理。做。 Basic Training 让你获得 React 的思维方式。那你应该看看redux,还有reduxs是如何工作的,redux-Saga可以不用redux,但它基本上是一个redux中间件。从这个开始:reactjs.org/docs/thinking-in-react.html,然后 redux redux.js.org,看看 Basic example 然后 async,dan 使用 thunk 作为中间件。当你了解 redux 是如何工作时,你可以看看 redux-Saga,老实说,你的 api 不是那么复杂,我宁愿用户 redux thunk
    • 你可能只想调度异步操作,而 redux-Saga 的生成器语法可能会令人困惑。并且请阅读“你可能不需要 redux”的部分,简单的 api 调用可以通过 isomproic fetch 和 react 来完成,redux 不需要。
    猜你喜欢
    • 2022-07-28
    • 2018-03-20
    • 2018-08-31
    • 2017-05-11
    • 1970-01-01
    • 1970-01-01
    • 2019-01-25
    • 2023-01-13
    • 1970-01-01
    相关资源
    最近更新 更多