React Native--通过fetch请求网络数据制作一个新闻App

    今天记录一个用React Native制作一个新闻App的过程,要做成的效果如下:

   

1、利用fetch请求网易数据接口

        在之前的网页开发中,经常使用ajax来异步请求网络数据,而在react中提倡使用fetch来进行网络通信,fetch发起网络请求的方式很简单:

 fetch(url);
        如果希望对请求的参数进行指定或者添加请求数据,fetch接收第二个参数:
fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',               //告诉服务器以json的形式接收响应数据
    'Content-Type': 'application/json',         //以json形式发送数据
  },
  body: JSON.stringify({                        //发送json数据
    firstParam: 'yourValue',
    secondParam: 'yourOtherValue',
  })
})

        还可以以传统网页的形式发送数据:

fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
  body: 'key1=value1&key2=value2'                  //网页表单形式发送数据
})
        fetch通过promise的形式对请求的响应进行处理,如果成功了,则执行.then()如果失败了执行.catch(),例如:
fetch(this.props.newsUrl)
  .then((response)=>response.json())              //将返回的数据转化为json格式
  .then((responseJson)=>{                         //接收转化后的json数据,保存到state中
    let rawData=responseJson[this.props.newsKey];
    this.setState({
      headerNews:rawData.slice(0,4),
      rowNews:rawData.slice(4)
    });
  })
  .catch((err)=>{                                 //对异常进行捕获、打印
    console.log(err);
  })
        其中newsUrl为网易的新闻api:
http://c.m.163.com/nc/article/headline/T1348647853363/0-25.html?from=toutiao&fn=2&passport=&devId=nTM86EPlcxZu09VdpTEh6aR3%2B%2FQX6x8vHBD3ne3k5bbgOrg%2FIP5DcguSDmtYyWbs&size=20&version=8.1&spever=false&net=wifi&lat=5OtqEKiivwW4K%2BGMt6DBdA%3D%3D&lon=jKlRVyYkSNti2wwsjGQHrw%3D%3D&ts=1463384311&sign=TtD7IZllDljVzBs2E4sa9fQyKTKF021w2EUC6qx1gEN48ErR02zJ6%2FKXOnxX046I&encryption=1&canal=appstore
  
        newsKey为其中的T1348647853363

    当fetch返回数据后先把它通过.json()方法转化为json格式,然后通过.then()接收转化后的json数据,把它保存到state中,我把前四条数据放在headerNews中用于渲染头部轮播图,后面的放在rowNews中,用于下面的每条新闻。

2、数据渲染

    头部的轮播图与之前做过的类似,我把它抽取为一个组件,之后把头部新闻数据this.state.headerNews传入即可,下面的每条新闻可以用FlatList来渲染,所以页面的框架如下:

return (
  <View style={styles.container}>
    <ScrollImage headerNews={this.state.headerNews} navigation={this.props.navigation}/>
    <FlatList
      ref={ref=>flatList=ref}
      keyExtractor = {(item, index) => index.toString()}
      data={this.state.rowNews}                         //数据源
      renderItem={this.renderItem.bind(this)}          //定义每条数据的渲染方法
      refreshControl={                                  //下拉刷新组件
        <RefreshControl
          refreshing={this.state.refreshing}            //通过state.refreshing控制是否刷新
          onRefresh={this._onRefresh.bind(this)}        //执行刷新函数
        />
      }
    />
  View>
);
        其中refreshControl用于定义下拉刷新组件,我使用react native提供的组件,其中通过refreshing来控制是否进行刷新,onRefresh来定义刷新时执行的方法
//下拉刷新数据
_onRefresh() {
  this.setState({refreshing: true});              //允许刷新
  this.getNewsData();                             //获取数据
  this.setState({refreshing:false});              //停止刷新
}

3、跳转到详情页

    主页Home分为列表页与详情页:

export default Home=StackNavigator(
  {
    List:{screen:HomeList},
    Detail:{screen:NewsDetail}
  },       

        StackNavigator会为注册的组件页面提供的navigation对象来进行页面之间的跳转,当在列表页点击某条新闻时,触发showDetail方法来实现跳转,并传入新闻的Id与标题:

//跳转到详情页
showDetail(item){
  this.props.navigation.navigate('Detail',{id:item.id,title:item.title});
}
        Detail页面通过React Native 的组件来渲染网页,
return (
  <WebView
    automaticallyAdjustContentInsets={true}
    source={{html: this.state.detailHtml, baseUrl: ''}}     //新闻详情页的数据源
    javaScriptEnabled={true}
    domStorageEnabled={true}
    startInLoadingState={true}
  />
)
        新闻的详细内容也从网易的api进行请求,每一条新闻数据对应一个newsId,跳转到详情页时传入了新闻的id,将id拼接到url可以访问网易新闻的数据接口从而拿到新闻的详细数据。
getNewsDetail(){
  let newsId=this.props.navigation.state.params.id;       //获取新闻id
  let url='http://c.3g.163.com/nc/article/' + newsId + '/full.html';    //拼接新闻详情的url
  fetch(url).then(response=>response.json())
    .then((responseJson)=>{
      let detail=responseJson[newsId];
      let imgArr=detail.img;                      //抽取数据中的图片数组
      let rawHtml=detail.body;                    //抽取数据中的body内容
      imgArr.forEach((imgItem)=>{                 //遍历图片数组将图片插入到body中
        let imgHtml='src+'" width="100%">';
        rawHtml=rawHtml.replace(imgItem.ref,imgHtml);
      });
      this.setState({
        detailHtml:rawHtml                        //将拼接好的网页body保存到state中
      });
    })
    .catch((err)=>{
      console.log(err);
    })
}
源码GitHub:https://github.com/SuperTory/React-Native-NewsApp

主要的文件位于components文件夹下


你可能感兴趣的:(WEB)