React Native - 从fetch()JSON渲染多个元素?

时间:2016-12-20 08:57:57

标签: ios reactjs react-native

编辑:我也在努力了解我应该采用什么样的结构以及如何在组件之间传递导航器等。如果您对我的代码有任何批评或反馈,也将受到高度赞赏!

所以我正在尝试从我的PHP API(接受POST数据并返回JSON)创建新闻源。 JSON:

{"status":"OK","news":[{"header":"some header","text":"some text"},{"header":"some other header","text":"some other text"},{"header":"yet another header","text":"some even more text"}]}

我想将此JSON提取到我的React Native应用程序中,并将每个新闻帖子写为视图。这个想法几乎就是一个博客。目前我试图做的事情不起作用。我可以成功获取JSON,但是,我不知道如何成功地将get_news()中的Main_logic.js中的JSON成为render()中的index.ios.js并打印出每个新闻帖子作为一个单独的视图元素。任何帮助都会非常感激!

这是我的index.ios.js中的render函数:

render(){

    //Components
    const Header = (
      <TouchableHighlight
      onPress={() => this.toggleSideMenu()}
      style={this.state.login_button_press ? styles.hamburger_pressed : styles.hamburger}
      onHideUnderlay={this._onHideUnderlay.bind(this)}
      onShowUnderlay={this._onShowUnderlay.bind(this)}
      >
        <View>
          <Icon
          name='menu'
          color='#FFFFFF'
          size={40}
          />
        </View>
      </TouchableHighlight>
    )
    const ContentView = (
      <Navigator
        initialRoute={{id: 'news'}}
        configureScene={this._configureScene}
        renderScene={(route, navigator) => {
            //Inloggningssidan
            if(route.id === "login"){
              return(
                <View style={{opacity: this.state.opacity}, styles.container}>
                  <Image resizeMode="center" style={styles.logo} source={require('./app/res/mbab_cmyk.png')} />
                  <TextInput
                    placeholder="Namn"
                    autocorrect={false}
                    style={styles.text_box}
                    onChangeText={(username) => {{GLOBALS.USERNAME = username}}}
                    returnKeyType="next"
                    onSubmitEditing={(event) => {
                      this.refs.password.focus();
                    }}
                  />
                  <TextInput
                    ref="password"
                    placeholder="Lösenord"
                    autocorrect={false}
                    secureTextEntry={true}
                    style={styles.text_box}
                    onChangeText={(password) => {{GLOBALS.PASSWORD = password}}}
                    returnKeyType="go"
                  />
                  <TouchableHighlight style={styles.login_button} onPress={() => MainLogic.login(navigator)}>
                      <Text style={styles.button_text}>Logga in</Text>
                  </TouchableHighlight>
                </View>
              );
            }
            else if(route.id === "news"){
              var news = MainLogic.get_news();

              return(
                <ScrollView style={{opacity: this.state.opacity}, styles.scroll_container}>
                  <Text style={styles.empty_text}>{news}</Text>
                </ScrollView>
              );
            }
            //Test sida
            else{
              return(
                <View style={styles.container}>
                  {Header}
                  <Text>TEST</Text>
                  <TouchableHighlight style={styles.button}>
                    <Text>Tryck på mig</Text>
                  </TouchableHighlight>
                </View>
              );
            }
          }
        }
      />
    )

    //App
    return (
      <View style={{backgroundColor: "#093360", flex: 1}}>
        <View style={{flex: 1, marginTop: 20}}>
          <StatusBar
            barStyle={"light-content"}
          />
          <SideMenu
          isOpen={this.state.sidemenu_is_open}
          style={styles.menu}
          menu={<this.Menu navigator={navigator}/>}
          >
            <View style={styles.header_bar}>
              {Header}
            </View>
            {ContentView}
          </SideMenu>
        </View>
      </View>
    );
  }

我还尝试将代码拆分为组件,以使其保持令人愉快的结构。 Index.ios.js:

import GLOBALS from './app/components/globals.js';
const MainLogic = require('./app/components/logic/main_logic.js');

以下是位于get_news()(MainLogic)中的函数Main_logic.js

get_news: function(){
      fetch(GLOBALS.API_URL, {
        method: "POST",
        headers: {
          'Accept': 'application/x-www-form-urlencoded',
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: "function=news&username=" + GLOBALS.USERNAME + "&password=" + GLOBALS.PASSWORD,
      })
      .then((response) => response.json())
      .then((response) => {
        try{
          if(JSON.stringify(response.status).replace(new RegExp('"', 'g'), '').match("OK")){
            GLOBALS.NEWS = response;
          }
          else{
            return "FEL";
          }
        }
        catch(e){
          AlertIOS.alert("error", e.message);
        }
      })
      .catch((e) => {
        console.warn(e);
      })
      .done();
  }

修改:回应amb:

news.js:

import React, { Component } from 'react';
import {
  View,
  Text,
  TouchableHighlight,
  ListView,
} from 'react-native';

import styles from './styles.js';
import GLOBALS from './globals.js';
const MainLogic = require('./logic/main_logic.js');

export default class News extends Component{
  constructor (props) {
    super(props)
    this.state = { news: [] }
  }

  componentDidMount(){
    // Modify your function to return a promise instead of a value
    MainLogic.get_news().then(response => {
      // setState will trigger a render with the received data
      this.setState({news: response});
    })
  }

  _renderRow(rowData, sectionID, rowID, highlightRow){
    return (
      <View>
        <Text>{rowData}</Text>
      </View>
    )
  }

  render(){
    return (
      <ListView
        dataSource={this.state.news}
        renderRow={this._renderRow()}
      />
    );
  }
}
get_news()中的

main_logic.js

get_news: async function(){
      fetch(GLOBALS.API_URL, {
        method: "POST",
        headers: {
          'Accept': 'application/x-www-form-urlencoded',
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: "function=news&username=" + GLOBALS.USERNAME + "&password=" + GLOBALS.PASSWORD,
      })
      .then((response) => response.json())
      .then((response) => {
        try{
          if(JSON.stringify(response.status).replace(new RegExp('"', 'g'), '').match("OK")){
            return response.news;
          }
          else{
            return "FEL";
          }
        }
        catch(e){
          AlertIOS.alert("error", e.message);
        }
      })
      .catch((e) => {
        console.warn(e);
      })
      .done();
  }

获取错误undefined is not an object (evaluating 'allRowIDs.length')

1 个答案:

答案 0 :(得分:1)

var news = MainLogic.get_news();是异步调用,因此如果您不等待它完成,您的news var中将永远不会有任何内容。

此块

var news = MainLogic.get_news();
return (
  <ScrollView style={{opacity: this.state.opacity}, styles.scroll_container}>
    <Text style={styles.empty_text}>{news}</Text>
  </ScrollView>
);

绝不会提供任何新闻。

您应该做的是拥有一个调用get_news函数的组件,并在响应到达时更改其状态。以此伪代码为例,按照注释注释:

class News extends React.Component {
  constructor (props) {
    super(props)
    this.state = { news: [] }
  }

  componentDidMount () {
    // Modify your function to return a promise instead of a value
    MainLogic.get_news().then(response => {
      // setState will trigger a render with the received data
      this.setState({news: response})
    }
  }

  render () {
    // You should use ListView instead of ScrollView, because
    // this.state.news will be an array and it can't be displayed
    // in a Text component.
    return (
      <ScrollView style={{opacity: this.state.opacity}, styles.scroll_container}>
        <Text style={styles.empty_text}>
          {this.state.news}
        </Text>
      </ScrollView>
    )
  }
}