如何使用React Native创建新闻阅读器:网页组件

在本系列的第一部分中,您学习了如何在机器上设置React Native,如何创建和使用自定义组件以及如何使用第三方库(例如moment.js) 。 在本教程中,您将学习如何使用fetch发出网络请求,如何使用内置的WebView组件呈现网页以及如何在物理设备上运行该应用程序。

1.提取API包装器

在本系列的第一部分中,我们使用了api函数,但尚未定义它。 首先创建一个src目录,并向其中添加一个文件api.js。 打开文件并添加以下内容:

module.exports = function(url){
    
    return fetch(url).then(function(response){
        return response.json();
    }).then(function(json){
        return json;
    });
}

该文件使用fetch功能,默认情况下,该功能在React Native中可用。 此功能允许该应用执行网络请求。 如果您使用过jQuery ,则它与$.ajax函数非常相似。 您指定一个URL和一些可选数据,然后会返回响应。

唯一的区别是您需要做一些额外的工作。 捕获第一个promise的函数将返回原始响应,这意味着您必须在response上调用json方法以获得返回JSON字符串的promise。 因此,您必须从中返回结果,并通过再次调用then函数来捕获promise, then传递将在promise解析后将被调用的函数。

然后,JSON字符串将作为参数传递给此函数,因此我们只返回它。 fetch方法返回一个promise,因此,当我们调用api方法时,我们仍然必须调用then方法来捕获实际响应,就像在本系列第一部分中所做的那样。

api(story_url).then(
    (story) => {
       ...
    }
);

2. WebPage组件

WebPage组件负责呈现网页。 它使用WebView组件执行此操作。

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  WebView
} = React;

var Button = require('react-native-button');
var GiftedSpinner = require('react-native-gifted-spinner');

var _ = require('lodash');

var WebPage = React.createClass({
    getInitialState: function() {
        return {
            isLoading: true
        };
    },

    render: function(){
            
        return (<View style={styles.container}>
        
            <View style={styles.webview_header}>
              <View style={styles.header_item}>
                <Button style={styles.button} onPress={this.back}>Back</Button>
              </View>
              <View style={styles.header_item}>
                <Text style={styles.page_title}>{this.truncate(this.state.pageTitle)}</Text>
              </View>
              <View style={[styles.header_item, styles.spinner]}>
                { this.state.isLoading && <GiftedSpinner /> }
              </View>
            </View>

            <View style={styles.webview_body}>
                <WebView 
                    url={this.props.url}
                    onNavigationStateChange={this.onNavigationStateChange}
                    
                />
            </View>
        </View>);

    },

    truncate: function(str){
        return _.truncate(str, 20);
    },

    onNavigationStateChange: function(navState) {
        
        if(!navState.loading){
            this.setState({
                isLoading: false,
                pageTitle: navState.title
            });
        }
    },
    
    back: function(){
       this.props.navigator.pop();
    }
});


var styles = StyleSheet.create({
    container: {
        flex: 1
    },
    webview_header: {
        paddingLeft: 10,
        backgroundColor: '#FF6600',
        flex: 1,
        justifyContent: 'space-between',
        flexDirection: 'row'
    },
    header_item: {
        paddingLeft: 10,
        paddingRight: 10,
        justifyContent: 'center'
    },
    webview_body: {
        flex: 9
    },
    button: {
        textAlign: 'left',
        color: '#FFF'
    },
    page_title: {
        color: '#FFF'
    },
    spinner: {

        alignItems: 'flex-end'
    }
});

module.exports = WebPage;

首先,我们通过创建所需变量并要求将要使用的库来进行一些内部管理。

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  WebView
} = React;

var Button = require('react-native-button');
var GiftedSpinner = require('react-native-gifted-spinner');

var _ = require('lodash');

接下来,我们创建WebPage组件。

var WebPage = React.createClass({
    ...
});

我们将isLoading设置为true作为默认状态。 此属性负责确定是否显示微调器。 默认情况下,微调框应可见以指示该页面正在加载。

getInitialState: function() {
    return {
        isLoading: true
    };
},

接下来,我们渲染组件。 像新闻项组件一样,该组件也具有标题和正文。 页眉包含一个后退按钮,页面标题和一个微调框。

render: function(){
        
    return (<View style={styles.container}>
    
        <View style={styles.webview_header}>
          <View style={styles.header_item}>
            <Button style={styles.button} onPress={this.back}>Back</Button>
          </View>
          <View style={styles.header_item}>
            <Text style={styles.page_title}>{this.truncate(this.state.pageTitle)}</Text>
          </View>
          <View style={[styles.header_item, styles.spinner]}>
            { this.state.isLoading && <GiftedSpinner /> }
          </View>
        </View>

        <View style={styles.webview_body}>
            <WebView 
                url={this.props.url}
                onNavigationStateChange={this.onNavigationStateChange}
            />
        </View>
    </View>);

},

该主体包含WebView组件。 WebView组件具有urlonNavigationStateChange属性。 url是先前从NewsItems组件中的viewPage函数传递的URL。 因此,当执行以下代码时:

this.props.navigator.push({name: 'web_page', url: url});

index.android.js中renderScene方法也将执行,并将URL传递给它:

renderScene: function(route, navigator) {

    var Component = ROUTES[route.name];
    return (
        <Component route={route} navigator={navigator} url={route.url} />
    );
},

这就是通过从this.props.url提取URL来访问URL的this.props.url

让我们回到添加到WebView组件的属性。 我们具有onNavigationStateChange属性,该属性用于指定每当Web视图导航到新页面时要执行的函数。 该函数如下所示:

onNavigationStateChange: function(navState) {
    
    if(!navState.loading){
        this.setState({
            isLoading: false,
            pageTitle: navState.title
        });
    }
},

调用上述函数时,将navState作为参数传递。 它包含有关Web视图当前状态的信息,例如页面标题以及当前是否正在加载。 这是更新状态的理想场所。 当页面不再加载时,我们将isLoading设置为false并为pageTitle设置一个值。

接下来,我们具有back功能,该功能使导航器返回上一页。 每当用户点击标题中的后退按钮时,都会调用此方法。

back: function(){
   this.props.navigator.pop();
}

truncate函数限制了传递给函数的内容的长度。 我们使用此功能来限制网页页面标题的文本。

truncate: function(str){
    return _.truncate(str, 20);
},

样式表如下所示:

var styles = StyleSheet.create({
    container: {
        flex: 1
    },
    webview_header: {
        paddingLeft: 10,
        backgroundColor: '#FF6600',
        flex: 1,
        justifyContent: 'space-between',
        flexDirection: 'row'
    },
    header_item: {
        paddingLeft: 10,
        paddingRight: 10,
        justifyContent: 'center'
    },
    webview_body: {
        flex: 9
    },
    button: {
        textAlign: 'left',
        color: '#FFF'
    },
    page_title: {
        color: '#FFF'
    },
    spinner: {
        alignItems: 'flex-end'
    }
});

最后,将组件暴露给外界:

module.exports = WebPage;

3.运行应用程序

要运行该应用程序,您需要一个Android设备或一个模拟器。 如果要使用仿真器,建议使用Genymotion 。 您可以通过执行以下命令来运行该应用程序:

react-native run-android

此命令将安装并启动应用程序。 但是,如果尝试这样做,则会出现以下错误:

运行应用

这是因为React Native希望React服务器可以在您的机器上运行。 每当您在文本编辑器中保存更改时,React服务器都会编译应用程序。 react-native run-android命令仅用于运行应用程序,以测试和调试应用程序。 这就是为什么它依赖React服务器来实际编译应用程序。

要消除该错误,您需要运行react-native start命令来启动服务器。 第一次运行会花费一些时间,但是到了要显示以下内容的部分:

<END>   Building Dependency Graph (35135ms)

您可以在项目目录上打开一个新的终端窗口,并执行adb shell input keyevent 82 。 这将在设备或仿真器中打开开发人员菜单。 菜单打开后,选择dev settings,然后选择debug server host&port

这将打开提示,要求您输入计算机的IP地址和端口。 找出您计算机的内部IP地址,并将其与端口8081一起输入提示,该端口是运行React服务器的默认端口。 换句话说,如果您的IP地址是192.168.254.254 ,则输入192.168.254.254:8081

之后,返回开发人员菜单并选择reload JS 。 这会重新加载应用程序,以便它检测到正在运行的React服务器实例。 该应用程序应该如何正常工作。

如果要在iOS设备上进行测试,请按照React Native网站上的指南进行操作

4.后续步骤

我们使用React Native构建了一个非常简洁的新闻阅读器应用程序。 下一步是什么? 如果您想了解更多有关React Native的信息,请参考以下几点:

  • 通过将应用分解为几个可重用的组件来改进代码。 首先查看重复的代码。 例如,在我们创建的应用程序中,我们复制了标题和其中的组件。 您可以做的是创建一个标题组件,该标题组件接受标题作为属性,然后在需要标题的每个页面上都需要它。
  • 通过创建一个服务器来缓存来自Hacker News API的项目,从而缩短应用程序的响应时间。 这样一来,您仅可以执行一个包含所有新闻项的网络请求,而不必像本教程中那样执行多个网络请求。
  • 生成签名的APK,以便您可以在Google Play上分发该应用。 对于iOS,您可以使用Xcode将应用分发到Apple的App Store。
  • 浏览有关访问本机设备功能(例如camera)的 API的文档
  • 在Github上查看Awesome React Native回购。 该仓库包含可用于React Native的组件,资源和工具的列表。
  • 如果您想了解有关React Native的新闻,请订阅React Native Newsletter

结论

而已。 在本教程中,您学习了如何与React Native一起创建一个与Hacker News API对话的新闻阅读器应用程序。 如果您有任何疑问,请将其放在下面的评论中,我会尽力解答。 您可以在GitHub找到本教程的源文件。 谢谢阅读。

翻译自: https://code.tutsplus.com/tutorials/how-to-create-a-news-reader-with-react-native-web-page-component--cms-25993

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值