今天记录一个用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、数据渲染
头部的轮播图与之前做过的类似,我把它抽取为一个组件<ScrollImage>,之后把头部新闻数据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提供的<RefreshControl>组件,其中通过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 的<WebView>组件来渲染网页,
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='<img src="'+imgItem.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文件夹下