【问题标题】:React Native - From fetch() JSON to render multiple elements?React Native - 从 fetch() JSON 渲染多个元素?
【发布时间】:2016-12-20 08:57:57
【问题描述】:

编辑:我也在努力理解我应该采用什么样的结构以及我应该如何在组件之间传递导航器等。如果您对我的代码有任何批评或反馈也将不胜感激!

所以我正在尝试从我的 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,但是,我不知道如何成功地将 JSON 从 Main_logic.js 中的 get_news() 获取到 index.ios.js 中的 render() 并将每个新闻帖子作为单独的视图元素打印出来。任何帮助将不胜感激!

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

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>
    );
  }

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

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

这是位于Main_logic.js(MainLogic)中的函数get_news():

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() in 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')

【问题讨论】:

    标签: ios reactjs react-native


    【解决方案1】:

    var news = MainLogic.get_news(); 是一个异步调用,所以如果你不等待它完成,你的news 变量中将永远不会有任何东西。

    这个区块

    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>
        )
      }
    }
    

    【讨论】:

    • 感谢您的回答!我已经更新了我的 OP,并在底部进行了编辑。我试图理解你的解释,但又被卡住了。我不确定我是否正确使用 ListView。对不起,如果这太简单了,就像我说我是 RN 新手!
    • 你需要调试你的代码。请检查您是否正确使用了从 API 返回的数据结构。您似乎在盲目地复制和粘贴建议的解决方案,而没有使其适应您的数据结构。我建议您检查您在您的状态中插入的内容以及您在rowData 中获得的内容。
    • 另外,您似乎还没有阅读ListView 文档,因为您没有使用它的数据源。请查看文档facebook.github.io/react-native/releases/0.39/docs/…
    • 感谢所有的帮助。尽管我承认我感到有些失落,但我正在努力理解。我将再次浏览文档并继续测试代码。尽管我很难理解,但我已经阅读了 ListView 上的文档。
    • 在将数据发送到ListView之前,您需要使用数据数组创建DataSource:const ds = new ListView.DataSource({rowHasChanged: (r1, r2) =&gt; r1 !== r2}); this.state = { dataSource: ds.cloneWithRows(['row 1', 'row 2']), };
    猜你喜欢
    • 2017-08-11
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 2020-03-01
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多