React Native从网络拉取数据并填充列表

本文工作,涉及到以下几个知识点

  • 请求网络并得到数据
  • 创建Button并触发按钮事件测试网络
  • 创建列表listview
  • 创建CELL
  • 根据返回的数据填充CELL

使用Fetch请求网络

React Native提供了和web标准一致的Fetch API,用于满足开发者访问网络的需求。如果你之前使用过XMLHttpRequest(即俗称的ajax)或是其他的网络API,那么Fetch用起来将会相当容易上手。这篇文档只会列出Fetch的基本用法,并不会讲述太多细节,你可以使用你喜欢的搜索引擎去搜索fetch api关键字以了解更多信息。

发起网络请求

要从任意地址获取内容的话,只需简单地将网址作为参数传递给fetch方法即可(fetch这个词本身也就是获取的意思):

fetch('https://mywebsite.com/mydata.json')

Fetch还有可选的第二个参数,可以用来定制HTTP请求一些参数。你可以指定header参数,或是指定使用POST方法,又或是提交数据等等:
提供两个可用的url,返回json
http://facebook.github.io/react-native/movies.json
http://bbs.reactnative.cn/api/category/3
可以替换下面的url

fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    firstParam: 'yourValue',
    secondParam: 'yourOtherValue',
  })
})

TIPS:本人用的是xcode8做测试,遇到网络请求不通的情况,解决方法是在info.plist加入一项允许http的请求,这是由于兼容ios9+的一种方式,通过看控制台的log知道访问的结果.
查看测试结果也可以利用工具Charles

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
</plist>


创建按钮并触发事件 TouchableHighlight

由于RN的特点,没有直接对Button封装出来,但是有可用的可点击组件,会相应点击事件。
中文网TouchableHightlight介绍
本组件用于封装视图,使其可以正确响应触摸操作。当按下的时候,封装的视图的不透明度会降低,同时会有一个底层的颜色透过而被用户看到,使得视图变暗或变亮。在底层实现上,实际会创建一个新的视图到视图层级中,如果使用的方法不正确,有时候会导致一些不希望出现的视觉效果。譬如没有给视图的backgroundColor显式声明一个不透明的颜色。

例子:

renderButton: function() {
  return (
    <TouchableHighlight onPress={this._onPressButton}>
      <Image
        style={styles.button}
        source={require('./button.png')}
      />
    </TouchableHighlight>
  );
},

注意:TouchableHighlight只支持一个子节点

如果你希望包含多个子组件,用一个View来包装它们。

所以结合上面的网络请求,我们的按钮触发事件可以这样写

  buttonTap=()=>{ 

    fetch( 'http://bbs.reactnative.cn/api/category/3')
   .then((response)=>response.json())
    .then((jsondata) =>{
        console.log(jsondata); 
        const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
   
        this.setState({dataSource: ds.cloneWithRows(jsondata.topics)});
        this.setState({title:jsondata.description});
         //alert(jsondata);
    })
    .catch((error)=>{
      alert(error);
      console.warning(error);
    });
  };

按钮的布局代码

  render() {
    return (
      <View style={[styles.container,{paddingTop: 22}]}>
          <TouchableHighlight style={{alignSelf:'flex-start'}} onPress={this.buttonTap} >
          <Image
            style={styles.button}
            source={require('./img/favicon.png')}
          />
    );
}

创建ListView

ListView组件用于显示一个垂直的滚动列表,其中的元素之间结构近似而仅数据不同。

ListView更适于长列表数据,且元素个数可以增删。和ScrollView不同的是,ListView并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。

ListView组件必须的两个属性是dataSourcerenderRowdataSource是列表的数据源,而renderRow则逐个解析数据源中的数据,然后返回一个设定好格式的组件来渲染。

下面的例子创建了一个简单的ListView,并预设了一些模拟数据。首先是初始化ListView所需的dataSource,其中的每一项(行)数据之后都在renderRow中被渲染成了Text组件,最后构成整个ListView

rowHasChanged函数也是ListView的必需属性。这里我们只是简单的比较两行数据是否是同一个数据(===符号只比较基本类型数据的值,和引用类型的地址)来判断某行数据是否变化了。

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

class ListViewBasics extends Component {
  // 初始化模拟数据
  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    this.state = {
      dataSource: ds.cloneWithRows([
        'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin'
      ])
    };
  }
  render() {
    return (
      <View style={{paddingTop: 22}}>
        <ListView
          dataSource={this.state.dataSource}
          renderRow={(rowData) => <Text>{rowData}</Text>}
        />
      </View>
    );
  }
}

// 注册应用(registerComponent)后才能正确渲染
// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
AppRegistry.registerComponent('ListViewBasics', () => ListViewBasics);

以上介绍了一个简单的ListView ,然而现实中的CELL并没有如此简单,我们需要重构CELL的组织方式


创建展示的CELL

如果学过RN的布局方式,定制化CELL就是个简单的事情,此处需要用到alighitmes,justifycontent,具体的可以参考 React Native 的布局方式flextbox

直接给出代码


class CELL extends Component{

  constructor(props){
    super(props);
    this.state = { detailTitle:'aaaa'};
  }
  render(){
    return(
          <View style={{flexDirection: 'column', backgroundColor:'#F5DD00'}}>
              <View style={{flexDirection: 'row',padding:10, justifyContent:'center',flex:1,alignItems:'center'}} >
                <Text style={{flex:2 ,marginLeft:10,marginRight:10,fontSize: 15}} >{this.props.title}</Text>
                <Text style={{flex:1,marginRight:10,color:'gray',fontSize: 12,textAlign:'right'}}>{this.props.detailTitle}</Text>
              </View>
              <View style={{height:.5,alignSelf:'stretch',backgroundColor:'gray'}}></View>
          </View>
      );
  }
}

要实现以上的需求,效果图如下

Paste_Image.png
  • 大伙可以先不看代码,自己组织代码试一下!
  • 有问题欢迎在下面留言
  • 不要吝啬自己的喜欢,有用的话点个赞吧

源代码如下:

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  TextInput,
  Image,
  View,ScrollView,
  ListView,
  TouchableHighlight,
} from 'react-native';


class RNCSDemo extends Component {
  // 初始化模拟数据
  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    this.state = {
      dataSource: ds.cloneWithRows([
        // 'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin'
      ])
    };
    this.buttonTap();//初始化
  }

 getMoviesFromApiAsync() {
    return fetch('http://facebook.github.io/react-native/movies.json',
      {
        headers:{
          'Accept': 'application/json',  
          'Content-Type':'application/json', 
        }
      })
      .then((response) => response.json())
      .then((responseJson) => {
        return responseJson.movies;
      })
      .catch((error) => {
        console.error(error);
      });
  }

  buttonTap=()=>{ 

    fetch( 'http://bbs.reactnative.cn/api/category/3'
      // , {
        // method: 'GET',
        // headers: {
          // 'Accept': 'application/json',
          // 'Content-Type': 'application/json',
        // },
        // body: JSON.stringify({ 
        // } )
    // }
    ).then((response)=>response.json())
    .then((jsondata) =>{
        console.log(jsondata); 
        const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
   
        this.setState({dataSource: ds.cloneWithRows(jsondata.topics)});
        this.setState({title:jsondata.description});
         //alert(jsondata);
    })
    .catch((error)=>{
      alert(error);
      console.warning(error);
    });

  };
  render() {

    return (
      <View style={[styles.container,{paddingTop: 22}]}>
          <TouchableHighlight style={{alignSelf:'flex-start'}} onPress={this.buttonTap} >
          <Image
            style={styles.button}
            source={require('./img/favicon.png')}
          />
        </TouchableHighlight>
        <Text  style={{textAlign:'center',alignSelf:'center'}} >{this.state.title}</Text>
        <ListView style={{flex:5}}
          dataSource={this.state.dataSource}
          renderRow={(rowData) => <CELL title={rowData.title} detailTitle={rowData.timestampISO}></CELL>}
        />
      </View>
    );
}
}

class CELL extends Component{

  constructor(props){
    super(props);
    this.state = { detailTitle:'aaaa'};
  }
  render(){
    return(
          <View style={{flexDirection: 'column', backgroundColor:'#F5DD00'}}>
              <View style={{flexDirection: 'row',padding:10, justifyContent:'center',flex:1,alignItems:'center'}} >
                <Text style={{flex:2 ,marginLeft:10,marginRight:10,fontSize: 15}} >{this.props.title}</Text>
                <Text style={{flex:1,marginRight:10,color:'gray',fontSize: 12,textAlign:'right'}}>{this.props.detailTitle}</Text>
              </View>
              <View style={{height:.5,alignSelf:'stretch',backgroundColor:'gray'}}></View>
          </View>
      );
  }
}

const styles= StyleSheet.create({ 

  container:{flex:1,
    justifyContent:'center',
    backgroundColor: '#F5FC00',}
});


AppRegistry.registerComponent('RNCSDemo', () => RNCSDemo);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容